我正在制作标签之间的简单彩色孪生动画
应该是这样的
我认为我接近正确的解决方案,但是当我在 Tab3 上切换时,没有任何效果
在每个选项卡中我都有一个
Animation<color>
但我不知道如何声明为新选项卡,或者当我擦到新选项卡并设置新选项卡ColorTween()
请帮助我,我不知道我是否应该为这 3 个选项卡创建一个新的 AnimationController 或只创建一个Animation<color>
这里是选项卡中动画的一些代码
@override
void initState() {
super.initState();
setAnimation();
}
setAnimation() {
if (widget.tabcontroller.animation.value == widget.tabindex ||
widget.tabcontroller.animation.value + 1 == widget.tabindex ||
widget.tabcontroller.animation.value - 1 == widget.tabindex) {
// set animation in which direction
animation = ColorTween(
begin: widget.tabcontroller.animation.value == widget.tabindex ? new Color(0xff622F74) : Colors.black26,
end: widget.tabcontroller.animation.value == widget.tabindex ? Colors.black26 : new Color(0xff622F74),
).animate(widget.tabcontroller.animation)
..addListener(() { setState(() {} ); });
}
}
和完整代码
class TabAnimation extends StatefulWidget {
@override
_TabAnimationState createState() => _TabAnimationState();
}
class _TabAnimationState extends State<TabAnimation> with TickerProviderStateMixin {
TabController _tabController;
@override
void initState() {
super.initState();
_tabController = TabController(vsync: this, length: 3);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primaryColor: Colors.lightBlue,
accentColor: Colors.orange,
),
home: DefaultTabController(
length: 3,
child: new Scaffold(
appBar: new AppBar(
title: new Text("TabAnimatedColorTween"),
bottom: new PreferredSize(
preferredSize: const Size(double.infinity, 48.0),
child : new Container(
color: Colors.white,
child: new TabBar(
labelColor: Colors.black87,
unselectedLabelColor: Colors.grey,
controller: _tabController,
tabs: <Widget>[
Tab(child: new _Tab(0, "Tab1", _tabController)),
Tab(child: new _Tab(1, "Tab2", _tabController)),
Tab(child: new _Tab(2, "Tab3", _tabController)),
],
),
),
),
),
body: TabBarView(
controller: _tabController,
children: <Widget>[
new Container(child: Center(child: new Text("1"))),
new Container(child: Center(child: new Text("2"))),
new Container(child: Center(child: new Text("3"))),
],
),
),
),
);
}
}
class _Tab extends StatefulWidget {
final int tabindex;
final String tabname;
final TabController tabcontroller;
_Tab(this.tabindex, this.tabname, this.tabcontroller, {Key key}) : super(key: key);
@override
__TabState createState() => __TabState();
}
class __TabState extends State<_Tab> {
int count;
Animation<Color> animation;
@override
void initState() {
super.initState();
setAnimation();
}
setAnimation() {
if (widget.tabcontroller.animation.value == widget.tabindex ||
widget.tabcontroller.animation.value + 1 == widget.tabindex ||
widget.tabcontroller.animation.value - 1 == widget.tabindex) {
// set animation in which direction
animation = ColorTween(
begin: widget.tabcontroller.animation.value == widget.tabindex ? new Color(0xff622F74) : Colors.black26,
end: widget.tabcontroller.animation.value == widget.tabindex ? Colors.black26 : new Color(0xff622F74),
).animate(widget.tabcontroller.animation)
..addListener(() { setState(() {} ); });
}
}
@override
Widget build(BuildContext context) {
return new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text(widget.tabname),
new Container(
alignment: AlignmentDirectional.center,
constraints: BoxConstraints(minHeight: 22.0, minWidth: 22.0),
margin: EdgeInsets.only(left: 5.0),
child: new Text(widget.tabindex.toString(), style: TextStyle(color: Colors.white70, fontSize: 10.0),),
decoration: new BoxDecoration(
shape: BoxShape.circle,
color: animation == null ? Colors.black26 : animation.value,
border: new Border.all(
width: 0.8,
color: Colors.white,
),
boxShadow: [
new BoxShadow(
color: Colors.black.withOpacity(0.4),
blurRadius: 5.0,
),
]
),
)
],
);
}
}
我解决了这个问题
我没有给 TabBar 添加新的动画。 我在 tabcontroller 中使用 Animation.value
颜色值在选项卡中获取
color: Theme.of(context).primaryColor.withOpacity(getCurrClr()),
来自 tabController 和当前选项卡的不透明度值
double getCurrClr() {
if(tabindex==0 && tabcontroller.animation.value < 1)
return 1 - tabcontroller.animation.value;
if(tabindex==1 && tabcontroller.animation.value <= 1)
return tabcontroller.animation.value;
if(tabindex==1 && tabcontroller.animation.value > 1)
return 2 - tabcontroller.animation.value;
if(tabindex==2 && tabcontroller.animation.value <= 2 && tabcontroller.animation.value > 1)
return tabcontroller.animation.value - 1;
return 0.0;
}
感谢您的解决方案FloW
这是对您的
getCurrClr()
功能的改进:
// returns opacity [0.0 .. 1.0] for a tab using animation value and tab index
double getCurrClr() {
final value = tabcontroller.animation!.value;
if (tabindex == 0 && value < 1) {
return 1 - value;
} else if (value <= tabindex && value > tabindex - 1) {
return value - (tabindex - 1);
} else if (value > tabindex && value < tabindex + 1) {
return (tabindex + 1) - value;
}
return 0.0;
}
这将适用于任意数量的选项卡,无论是三个选项卡还是 15 个选项卡。
试试这个
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class PyWidgetTestPage extends StatefulWidget {
PyWidgetTestPage({Key key, routerArguments}) : super(key: key);
@override
_PyWidgetTestPageState createState() => _PyWidgetTestPageState();
}
class _PyWidgetTestPageState extends State<PyWidgetTestPage> with TickerProviderStateMixin {
TabController controller; //= TabController(length: 14, vsync: this);
AnimationController anicontroller;
Animation animation;
Animation<int> intAnim;
Animation<Color> colorAni;
@override
void initState() {
// TODO: implement initState
super.initState();
controller = TabController(length: 14, vsync: this);
;
// ColorTween(
// // begin: Colors.black26,
// // end: new Color(0xff622F74),
// // ).animate(_conrtoller)
// // ..addListener(() {
// // print("set stats");
// // setState(() {});
// // });
// // _conrtoller.forward();
// anicontroller = AnimationController(duration: const Duration(milliseconds: 10000), vsync: this);
// anicontroller.addListener(() {
// print("controller=====${anicontroller.value}");
// });
// anicontroller.addStatusListener((status) {
// print("status====$status");
// });
// intAnim = IntTween(begin: 0, end: 200).animate(anicontroller)
// ..addListener(() {
// setState(() {});
// })
// ..addStatusListener((status) {});
// // colorAni = ColorTween(begin: Colors.purpleAccent, end: Colors.orange).animate(anicontroller)
// // ..addListener(() {
// // setState(() {});
// // })
// // ..addStatusListener((status) {});
// anicontroller.forward();
}
@override
Widget build(BuildContext context) {
// return Scaffold(
// appBar: new AppBar(
// backgroundColor: colorAni?.value ?? Colors.purple,
// title: new Text("adfadf"),
// ),
// body: Column(children: [
// Text("${intAnim?.value ?? "ssss"}"),
// ]),
// );
return TabAnimation();
}
}
class TabAnimation extends StatefulWidget {
@override
_TabAnimationState createState() => _TabAnimationState();
}
class _TabAnimationState extends State<TabAnimation> with TickerProviderStateMixin {
TabController _tabController;
GlobalKey<__TabState> keyA = GlobalKey();
GlobalKey<__TabState> keyB = GlobalKey();
GlobalKey<__TabState> keyC = GlobalKey();
@override
void initState() {
super.initState();
_tabController = TabController(vsync: this, length: 3);
_tabController.addListener(() {
print("-------");
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primaryColor: Colors.lightBlue,
accentColor: Colors.orange,
),
home: DefaultTabController(
length: 3,
child: new Scaffold(
appBar: new AppBar(
title: new Text("${Icons.animation}"),
bottom: new PreferredSize(
preferredSize: const Size(double.infinity, 48.0),
child: new Container(
color: Colors.white,
child: new TabBar(
onTap: (int value) {
print("adfadf $value");
keyA.currentState.setAnimation(value == 0); //调用子控件方法
keyB.currentState.setAnimation(value == 1); //调用子控件方法
keyC.currentState.setAnimation(value == 2); //调用子控件方法
},
labelColor: Colors.black87,
unselectedLabelColor: Colors.grey,
controller: _tabController,
tabs: <Widget>[
Tab(
child: new _Tab(
0,
"Tab1",
_tabController,
key: keyA,
)),
Tab(
child: new _Tab(
1,
"Tab2",
_tabController,
key: keyB,
)),
Tab(
child: new _Tab(
2,
"Tab3",
_tabController,
key: keyC,
)),
],
),
),
),
),
body: TabBarView(
controller: _tabController,
children: <Widget>[
new Container(child: Center(child: new Text("1"))),
new Container(child: Center(child: new Text("2"))),
new Container(child: Center(child: new Text("3"))),
],
),
),
),
);
}
}
class _Tab extends StatefulWidget {
final int tabindex;
final String tabname;
final TabController tabcontroller;
_Tab(this.tabindex, this.tabname, this.tabcontroller, {Key key}) : super(key: key);
@override
__TabState createState() => __TabState();
}
class __TabState extends State<_Tab> with TickerProviderStateMixin {
int count;
bool isSelected;
Animation<Color> animation;
AnimationController _conrtoller; // = AnimationController(duration: Duration(milliseconds: 300), vsync: this);
@override
void initState() {
super.initState();
_conrtoller = AnimationController(duration: Duration(milliseconds: 300), vsync: this);
;
isSelected = widget.tabindex == 0;
setAnimation(widget.tabindex == 0);
}
setAnimation(bool selected) {
if (isSelected == selected) {
return;
}
isSelected = selected;
print("widget index ${widget.tabindex} selectedc: $selected");
_conrtoller?.dispose();
_conrtoller = AnimationController(duration: Duration(milliseconds: 300), vsync: this);
animation = ColorTween(
begin: selected ? Colors.black26 : new Color(0xff622F74),
end: selected ? new Color(0xff622F74) : Colors.black26,
).animate(_conrtoller)
..addListener(() {
print("set stats");
setState(() {});
});
_conrtoller.forward();
}
@override
Widget build(BuildContext context) {
print("build${widget.tabindex}");
return new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text(widget.tabname),
new Container(
alignment: AlignmentDirectional.center,
constraints: BoxConstraints(minHeight: 22.0, minWidth: 22.0),
margin: EdgeInsets.only(left: 5.0),
child: new Text(
widget.tabindex.toString(),
style: TextStyle(color: Colors.white70, fontSize: 10.0),
),
decoration: new BoxDecoration(
shape: BoxShape.circle,
color: animation == null ? Colors.black26 : animation.value,
border: new Border.all(
width: 0.8,
color: Colors.white,
),
boxShadow: [
new BoxShadow(
color: Colors.black.withOpacity(0.4),
blurRadius: 5.0,
),
]),
)
],
);
}
}