乐趣区

Flutter尝鲜2——动画处理

本例的代码参考这里。
概述
动画处理的基本原理是,对组件 (widget) 的某个或某组属性设置一组连续变化的值,这些值在一定时间间隔内不断被应用到该属性上,使得组件的外观看上去在进行平滑而连续的变动。
例如 2 秒内每隔 0.1s 将一个组件的 x 轴坐标加 1,那么该组件看上去就是从左至右移动了 2 秒共 20 个单位。
处理组成部分
具体到 Flutter,动画处理主要分为三个部分:

动画控制器(AnimationController),控制整个动画运行,包括开始结束和动画时长等。
动画抽象(Animation),描述了动画运动的速率,例如组件是加速还是匀速,或者其它变化。
变动范围(Tween),定义了动画组件属性值的变化范围,例如从坐标 (0, 0) 移动到(20, 0)

处理流程
上述三大组件,控制了整个动画的运行。用文字描述,其流程主要包括:

初始化动画控制器,设定动画的时长,初始值等(如上例:2 秒时长)
初始化变动范围(如上例:Offset 从 [0, 0] 到[20, 0])
初始化动画抽象,定义它的运动速率(如上例:匀速变动)
将动画描述的值,赋值到动画组件的对应属性上
开始执行动画(调用动画控制器的开始方法)
动画执行结束

AnimationController 定义
AnimationController 是一个特殊的 Animation 对象。创建一个 AnimationController 时,需要传递一个 vsync 参数。设置此参数的目的,是希望屏幕每一帧画面变化时能够被通知到。也就是说,屏幕刷新的每一帧,AnimationController 都会生成一个新的值(同样也意味着,如果在屏幕外那么就不被触发)。这样动画组件就能够完成一个连续平滑的动画动作。
Tickers can be used by any object that wants to be notified whenever a frame triggers。
AnimationControler 通常是在一个 StatefulWidget 中被声明,并且附带一个叫做 SingleTickerProviderStateMixin 的 Mixin(原因就在上面说的,要设置 vsync 参数)。
class AnimationDemo extends StatefulWidget {
AnimationDemoState createState() => AnimationDemoState();
}

class AnimationDemoState extends State<AnimationDemo> with SingleTickerProviderStateMixin {

AnimationController controller;

@override
void initState() {
super.initState();

controller = AnimationController(duration: Duration(milliseconds: 2000), vsync: this);

}

@override
void dispose() {
controller.dispose(); // 离开时需要销毁 controller
super.dispose();
}

}
当 Animation 和 Tween 的设置完成后,简单调用 controller.forward()即可开始动画。
Tween 定义
Tween 就是要改变的属性值的变动范围。它可以是任意的属性类如 Offset 或者 Color,最常见的是 double。

AnimationController controller;
Tween<double> slideTween = Tween(begin: 0.0, end: 20.0);

Animation 定义
Animation 对象本身可以看做是动画中所有变化值的一个集合。它包含了变化区间内的所有可取值,并返回给动画组件当前的变动值。
Animation 在使用中要设置的,是他的变动速率,如 Curves.linear(线性变化)。

AnimationController controller;
Tween<double> slideTween = Tween(begin: 0.0, end: 20.0);
Animation<double> animation;

@override
void initState() {
super.initState();


animation = slideTween.animate(CurvedAnimation(parent: controller, curve: Curves.linear));
}

动画组件定义
为了说明简单,在 build 方法中嵌套两个 Container 组件,外部容器 Container 的 paddingLeft 跟随动画变动,达到移动内部 Container 的目的。
class AnimationDemoState extends State<AnimationDemo> with SingleTickerProviderStateMixin {

@override
Widget build(BuildContext context) {
return Container(
width: 200,
alignment: Alignment.centerLeft,
padding: EdgeInsets.only(left: animation.value),
child: Container(
color: Colors.blue,
width: 80,
height: 80,
),
);
}
}
启动动画
在启动动画之前有一个 Flutter 的基本概念要说明。做过 React 的同学很清楚,要想 render 方法重新执行,要么 props 有更新要么 state 有更新。在 Flutter 也同样如此,build 方法同样依赖于 state 的更新才能重新执行。
在 AnimationController 的说明中,我们知道因为设置了 vsync 所以屏幕刷新的每一帧都会更新它的值。所以可以在 Controller 上加上一个 listener,每次有 update 都调用一下 setState,以此达到重新渲染 UI 的目的。

@override
void initState() {

animation.addListener(() => this.setState(() {}));

controller.repeat(); // 动画重复执行
}
调用 controller.repeat()方法,动画会被反复执行。如果想只执行一次,那么可以使用 controller.forward();

退出移动版