在动画过程中,需要两个部分:
- 第一个就是动画控制类,它不需要知道在屏幕上显示什么。
- 第二个就是实际上的UI元素
1. 动画控制类
动画控制类有两部分:
-
Animation
Animation
类对象是一个抽象类,支持泛型,我们常用的是Animation<double>
,当然这里不仅仅是double,可以是任意一个对象。Animation对象本身和UI渲染没有任何关系,而是用于生产动画过程中的值,用这个值来控制动画,也能获取当前动画的状态(正在播放中,还是结束等),也能获取动画播放过程中的当前值。而且Animation
类有很多不同的子类,用于实现不同的动画效果,我们下篇在将。 -
AnimationController
AnimationController
一方面是用来管理Animation
,比如动画的开关,另一方面,AnimationController
和Animation
还有另外一种关系,就是AnimationController
是输入,是X,它的范围是从0.0到1.0的数字,经过Animation
里定义的f(),映射到对应的Y值,
所以Animation
和AnimationController
是在动画中比不可少的元素,而且这两个一定是搭配使用的。看代码:
//定义的AnimationController,动画时长2000ms
AnimationController controller = AnimationController(
vsync: this, duration: const Duration(milliseconds: 2000));
//Tween是Animation的子类,其实是定义了一种f(),Y的值是从50到200
//.animate(controller)是一定要调用的
Animation<double> animation = Tween(begin: 50.0, end: 200.0).animate(controller);
//动画控制,开始播放
controller.forward();
复制代码
2 使用动画
讲完了动画控制类,这个动画控制类怎么运用到UI元素上呢?
总共有三种方法:
- 原始方法
将Animation
的值直接用到widget的属相上,用这种方法时,一定要记得Animation
里要添加动画的监听addListener
方法,addListener
方法里要调用setState(() {})
。
因为虽然Animation
的值变了,但如果不调用setState(() {})
的话,widget就不会重新绘制。
class AnimApp extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _AnimAppState();
}
}
class _AnimAppState extends State<AnimApp> with SingleTickerProviderStateMixin {
AnimationController controller;
Animation<double> animation;
@override
void initState() {
super.initState();
controller = AnimationController(
vsync: this, duration: const Duration(milliseconds: 2000));
animation = Tween(begin: 50.0, end: 200.0).animate(controller)
..addListener(() {
setState(() {});
});
controller.forward();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
width: animation.value,
height: animation.value,
decoration: BoxDecoration(color: Colors.redAccent),
),
));
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
}
复制代码
-
AnimatedWidget
AnimatedWidget
是Flutter将动画封装成了Widget,更方便使用,而且不需要调用setState()
,AnimatedWidget
也有很多子类,这次先不介绍,先看它的普通使用,AnimatedWidget
需要一个Animation
的参数:
class AnimApp extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _AnimAppState();
}
}
class _AnimAppState extends State<AnimApp> with SingleTickerProviderStateMixin {
AnimationController controller;
Animation<double> animation;
@override
void initState() {
super.initState();
controller = AnimationController(
vsync: this, duration: const Duration(milliseconds: 2000));
animation = Tween(begin: 50.0, end: 200.0).animate(controller);
controller.repeat();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: AnimApp2(animation: animation,),
);
}
}
class AnimApp2 extends AnimatedWidget {
AnimApp2({Key key, Animation<double> animation})
: super(key: key, listenable: animation);
@override
Widget build(BuildContext context) {
final Animation<double> animation = listenable;
return Scaffold(
body: Center(
child: Container(
width: animation.value,
height: animation.value,
decoration: BoxDecoration(color: Colors.redAccent),
),
));
}
}
复制代码
-
AnimatedBuilder
前面的
AnimatedWidget
,我要是每实现一个动画就单独抽出来一个class文件来写Widget,太复杂了,所以有了AnimatedBuilder
,AnimatedBuilder
可以更方便的为Widget添加动画,看代码:
class AnimApp extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _AnimAppState();
}
}
class _AnimAppState extends State<AnimApp> with SingleTickerProviderStateMixin {
AnimationController controller;
Animation<double> animation;
@override
void initState() {
super.initState();
controller = AnimationController(
vsync: this, duration: const Duration(milliseconds: 2000));
animation = Tween(begin: 50.0, end: 200.0).animate(controller);
controller.repeat();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: AnimatedBuilder(
animation: animation,
builder: (context, child) {
return Center(
child: Container(
width: animation.value,
height: animation.value,
decoration: BoxDecoration(color: Colors.redAccent),
),
);
},
),
);
}
}
复制代码