动画概述
对于任何UI框架,实现动画的原理都是一样的,通过画面在短时间内的变化形成动画,基本上人眼对30帧以上的动画的感受就是极限了,即在30帧以上人眼是基本区别不了的,在Flutter中,动画的平均帧率是可以达到60FPS的,这和原生基本持平,也是Flutter的一个特点。
主要涉及到的类
在Flutter中,实现动画主要涉及到四个类,分别是Animation,Curved,Tween,Controller。
其中Animation类是用来保存动画的插值和状态的
Curved是用来实现动态的变化方式,比如说一般变化是线性的,你可以通过设置不同Curved来实现不同的函数变化方式。
Tween,在默认情况下,AnimationController对象的值范围是在0.0到1.0之间,我们可以通过设置Tween来设置动画的值的变化范围以达到我们想要的效果。
Controller,用来控制动画的控制器。
Animation
Animation对象本身和UI渲染没有关系,它是用来保存动画插值和状态的对象,我们可以查看Animation源码
1 | abstract class Animation<T> extends Listenable implements ValueListenable<T> { |
Animation对象是一个在一段时间内一次生成一个区间(Tween)之间值的类,这种输出可以是线性的,曲线的(我们可以通过Curved来设置),这个类中还为我们定义了一些监听器和状态监听器,我们可以通过设置监听器来监听动画发生的一些变化,然后做出一些改变。
- addListener()可以给Animation添加帧监听器,在每一帧都会被调用。帧监听器中最常见的行为是改变状态后调用setState()来触发UI重建。
- addStatusListener()可以给Animation添加“动画状态改变”监听器;动画开始、结束、正向或反向(见AnimationStatus定义)时会调用StatusListener。
Tween
刚刚提到了Animation是用来生成在Tween之间的值的对象。
我们先来查看一下源码
1 | class Tween<T extends dynamic> extends Animatable<T> { |
因为Tween继承Animatable这个抽象类,这个抽象类中有一个方法animate方法,它用来返回一个Animation对象,所以对于Tween类我们通常设置完begin和end之后会调用原本继承于Animatable抽象类的animate方法设置一个Animation对象并赋值给一个Animation对象。
Curve
Curve这个类是用来设置动画的变化曲线的,默认情况下是线性变化的。
我们一般使用CurveAnimation这个对象来自定义设置动画曲线,我们可以查看一下它的源码。
1 | class CurvedAnimation extends Animation<double> with AnimationWithParentMixin<double> { |
对于CurveAnimation我们可以直接使用构造方法来指定父controller和想要实现的curve
AnimationController
用来实现动画的控制器,它包含动画的启动forward()、停止stop() 、反向播放 reverse()等方法。AnimationController会在动画的每一帧,就会生成一个新的值。默认情况下,AnimationController在给定的时间段内线性的生成从0.0到1.0(默认区间)的数字。
1 | AnimationController({ |
Ticker
当创建一个AnimationController时,需要传递一个vsync参数,它接收一个TickerProvider类型的对象,它的主要职责是创建Ticker,定义如下:
1 | abstract class TickerProvider { |
Flutter应用在启动时都会绑定一个SchedulerBinding,通过SchedulerBinding可以给每一次屏幕刷新添加回调,而Ticker就是通过SchedulerBinding来添加屏幕刷新回调,这样一来,每次屏幕刷新都会调用TickerCallback。使用Ticker(而不是Timer)来驱动动画会防止屏幕外动画(动画的UI不在当前屏幕时,如锁屏时)消耗不必要的资源,因为Flutter中屏幕刷新时会通知到绑定的SchedulerBinding,而Ticker是受SchedulerBinding驱动的,由于锁屏后屏幕会停止刷新,所以Ticker就不会再触发。
通过将SingleTickerProviderStateMixin添加到State的定义中,然后将State对象作为vsync的值,这在后面的例子中可以见到。
使用例子
这里我们实现一个Icon通过动画的值来变化大小和颜色的动画
1 | class AnimateLove extends StatefulWidget { |