flutter中的动画千变万化,但是始终不过2种:‘隐式动画’与‘显示动画’。
什么是隐式动画?
不需要手动控制的动画。所谓的隐式
就是指控制动画的过程由系统帮你完成了。可以给它比作太阳,它天生就能动(其实底层也是通过显示动画
那套实现的)。
它的特点是:
- 自动控制;
- 简单(2句代码就可以实现动画);
- 典型代表:
AnimatedContainer
、AnimatedOpacity
等以Animated
开头的组件
上代码:
AnimatedSize( //第一句。
duration: Duration(seconds: 1), // 第二句。
child: Container(
width: 100, // 首次运行后改动这个值为200,然后按保存按钮,就会看见动画
height: 100,// 首次运行后改动这个值为200,然后按保存按钮,就会看见动画
color: Colors.blue,
),
)
当然,实际中肯定不是按保存按钮执行动画!不过其实也差别不大,只是你自己用代码改变child的大小而已,这个动画就会自己动起来。(由于太过简单,不需要再多解释了)
什么是显示动画?
需要手动控制动画。所谓的显示
就是指需要自己搞一个AnimationController
来控制动画。可以给它比作一个汽车,需要引擎来让轮子转起来。
它的特点是:
- 使用
AnimationController
显式控制; - 更灵活,但需要自己管理动画生命周期;
- 典型代表:
AnimatedBuilder
、AnimatedWidget
上代码:
class _MyAnimState extends State<MyAnim> with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _animation;
@override
void initState() {
super.initState();
// 创建动画控制器
_controller = AnimationController(
duration: Duration(seconds: 1),
vsync: this,
);
// 创建动画
_animation = Tween<double>(
begin: 0,
end: 200,
).animate(_controller);
}
@override
Widget build(BuildContext context) {
return Column(
children: [
AnimatedBuilder(
animation: _animation,
builder: (context, child) {
return Container(
width: _animation.value,
height: _animation.value,
color: Colors.blue,
);
},
),
ElevatedButton(
onPressed: () {
// 手动控制动画
if (_controller.status == AnimationStatus.completed) {
_controller.reverse();
} else {
_controller.forward();
}
},
child: Text('触发动画'),
),
],
);
}
}
代码里的with SingleTickerProviderStateMixin
是什么呢?
还是用前面提到的汽车来举例:我们知道,系统是一直在运行的,它本身就相当于一个引擎。当我们with
上这个SingleTickerProviderStateMixin
之后,就相当于给汽车挂了个档(开机就是打火,引擎其实早就启动了),相当于告诉操作系统:你运行的动力我们也需要用到了,也可以说是给操作系统的引擎运动函数加了个回调而已。
所以,我们的方向盘就是AnimationController
(注:vsync
就是连接了SingleTickerProviderStateMixin
),我们现在有了AnimationController
可以控制动画了,它本身也有驱动的动力了。
现在我们有了第一个需求:启动
controller.forward(); // 启动
//顺便学会其他几个
controller.reverse(); // 倒车
controller.stop(); // 停车
controller.reset(); // 前面不算,重来
光会前进是不够的,我们还要会:转弯与加减速
// 添加加速减速的效果。比真实开车更强的是它的加减速有好多预设模式:Curves.bounceOut、Curves.slowMiddle等;
final curvedAnimation = CurvedAnimation( parent: controller, curve: Curves.bounceOut);
比如Curves.bounceOut
的样子是这样:
我们知道,挂上1档
与5档
的车速其实是不一样的,那在flutter
里是怎么换档
的?
那就是Tween
:
// 连接上前面的controller
// 当 controller.value 是 0.0 时,输出 0
// 当 controller.value 是 1.0 时,输出 200
Tween<double> tween = Tween<double>( begin: 0, end: 200);
其实到这里也说得差不多了,最终的动画是通过AnimatedBuilder
之类的应用到实际页面上面的。
现在就剩最后一个问题:这4个有什么关系?
我们可以通过下面这个图来解释一下:
通过Controller
提供动力和操控(Controller
的动力来源是它与SingleTickerProviderStateMixin
连接起来的),通过Curve
来调节方向与速度,通过Tween
来换档,最后通过Animation
把最终的效果应用到实际以达到页面按需动起来的目的。
补充:
Controller
有lowerBound
和upperBound
2个构造参数来把范围作一下调整,这样简单的话(简单是指单个动画,其实还有多个动画串联和并联)可以把Tween
给省略掉(直接使用controller.value
);Tween
不仅仅可以把Controller
的数字转换为数字,还可以是颜色等;- 预设的模式真的很多,还有
SawTooth
、Interval
等等各式花哨的Curve
,实在不满足就自己自定义也行。