文章目录

  • 动画
  • addListener
  • addStatusListener
  • 动画控制器
  • Tweens插值器
  • 架构
  • Scheduler调度器
  • Tickers
  • 模拟器
  • Animatables
  • Tween
  • 组合 animatables
  • 曲线
  • Aniamtions
  • 组合 animations
  • Animation Controllers
  • 将animatables Attach到animations



Flutter的动画系统是基于一组

Animation类型的对象。Widget既可以在它们的build函数中通过读取它们当前的值,监听它们的状态变化来创建动画,也可以将动画传递到其他widget中,作为实现更复杂动画的基础。

动画

Animation类是动画系统中主要的构建单元。动画表示一个可以随着动画的生命周期改变的特定类型值。大多数执行动画的widget需要接收一个Animation对象作为参数,从中可以读取Animation对象的当前的值,并在这个对象上监听这个值的变化。

addListener

当动画的值改变时,动画都会通知所有调用addListener注册进来的观察者。通常,监听到一个动画的State对象,在它的监听回调方法内,会调用它自己的setState方法,通知widget系统它需要根据动画的新值重建。
这里有两种widget:AnimateWidgetAnimateBuilder。通常使用这两个类来帮助widgets重建。AnimatedWidget对无状态动画部件最有用。通常你需要继承AnimateWidget,并覆写build方法。而AnimatedBuilder类则适用于那些希望将动画作为更大build函数一部分而被包含在内的复杂部件。如果要使用AnimatedBuilder,你需要构造widget 作为目标widget,并传给它一个builder函数。

addStatusListener

Animations 也提供了AnimationStatus,AnimationStatus指示了动画是如何随着时间而推演的。当动画的状态改变的时候,动画会通知所有通过addStatusListener注册进来的观察者。通常,动画的初始状态是dismissed。例如,从0.0到1.0的动画,当它的值是0.0时,状态是dismissed。接着动画可能会调用forward(比如,从0.0到1.0变化)或者reverse(比如,从1.0到0.0变化)。最终,如果动画达到了取值范围的终点(例如,1.0),动画的状态会变成completed。

动画控制器

要创建一个动画,首先要创建一个AnimationController。AnimationController除了本身就是一个动画外,它还可以用来控制动画。例如,你可以告诉controller调用forward来播放动画,或者调用stop停止。你也可以调用fling,来驱动动画模拟一个物理运动,比如弹簧。
一旦你创建了一个AnimationController,你就可以开始基于它构建其他的动画。例如,你可以创建一个ReverseAnimation,ReverseAnimation用于镜像原始的动画,它会朝相反的方向运行(例如,从1.0到0.0)。类似地,你可以创建一个CurvedAnimation,CurvedAnimation的值呈曲线(curve)变化。

Tweens插值器

为了可以在超过0.0到1.0的区间外做动画,你可以使用Tween,Tween在它的beginend范围内插值。许多类型都有专门的Tween的子类来提供特定类型的插值。例如,ColorTween在颜色值之间插值,RectTween在rect之间插值。通过继承Tween类并覆写它的lerp方法来自定义属于你的的插值器。
tween本身只定义了如何在两个值之间插值。要从动画的当前帧得到具体值,还需要动画来确定当前状态。为得到一个确切值,有两种结合tween和动画的方式:

  1. 你可以根具动画的当前值估计(evalute)tween。这个方法对那些已经监听着这个动画的widget最有用,因此你可以在动画值改变时重建widget。
  2. 你可以基于这个动画animate tween。这个animate方法并不是返回一个单值,而是返回一个新的组合了这个tween的Animation对象。当你想把这个新创建的动画传递给另一个widget时,这个方法最有用。一旦如此,那么这个widget就可以结合tween来读取当前的值,并且监听值的改变。

架构

Animation实际上由一些核心的模块组建。

Scheduler调度器

SchedulerBinding是一个展示Flutter调度原语的单例类。
在这里,关键原语是帧回调。每当一帧需要显示在屏幕上时,Flutter引擎会触发一个“开始帧”回调callback,调度器把这个回调callback多路复用到所有使用scheduleFrameCallback()注册的观察者。所有这些回调都有一个该帧的,以Duration形式的官方时间戳作为入参。因此所有的回调都有相同的时间戳,所以从这些回调触发的动画都会精确地同步,即使它们执行了几毫秒。

Tickers

Ticker类hook了调度器的scheduleFrameCallback()机制,以在每个tick(滴答)时回调callback。
Ticker可以被启动和停止。当启动时,它返回一个Future,这个Future会在Ticker被停止时解析。
Ticker会在每个tick时向callback提供从第一个tick以来已经持续的时间。
因为在ticker启动后,ticker总是给出它们相对于第一次tick以来流逝的时间,所以所有的ticker总是同步的。如果你在两帧之间的时间里,先后启动了三个ticker,它们都将以相同的开始时间同步,并随后以相同的步调tick滴答。

模拟器

Simulation(模拟器)抽象类将一个相对的时间值(流逝过的时间)映射为一个double值,并且有一个结束的概念。
原则上模拟器(simulations)是无状态的,但实际上一些模拟器(例如,BouncingScrollSimulationClampingScrollSimulation)当被查询的时候会不可逆的改变状态。
这里有各种个样的Simulation类,实现了不同的效果。

Animatables

Animatable抽象类将一个double值映射到一个特定类型的值。
Animatable类是无状态的,并且是不可变的。

Tween

Tween抽象类将名义上在0.0-1.0范围内的值映射到一个类型化的值(例如,一个Color值,或者其他double值)。Tween就是一个Animatable。
它有一个输出类型为(T)的概念,并有一对该类型的begin和end值,对于给定的输入值(介于0.0-1.0),tween定义了一个从begin到end插值的方法。
Tween类是无状态的,并且不可变。

组合 animatables

传递一个Animatable(父级)到一个Animatable的chain()方法中,创建一个新的Animatable子类,该子类先应用父项的映射,然后应用子项的映射。

曲线

Curves抽象类将一个0.0-1.0的double值映射到一个另一个介于0.0-1.0区间的某个值。
Curve类是无状态和不可修改的。

Aniamtions

Animation抽象类提供了一个给定类型的值,一组动画方向和动画状态的概念,以及一个监听器接口来注册回调,当动画的值或者状态改变时,回调会被调起。
一些Animation的子类有从来不变的值(kAlwaysCompleteAnimation, kAlwaysDismissedAnimation, AlwaysStoppedAnimation);在这些类上注册回调是没有效果的,这些回调不会被调用。
Animation是一个特殊的变体,因为它可以被用于表示一个介于0.0-1.0的double类型值,该值是Curve和Tween类,以及某些Animation的子类所期望的输入值。
有些Animation子类是无状态的,仅仅只是将侦听器转发给它们的父级。有些是有状态。

组合 animations

多数Animation子类持有一个父亲Animation。它们由自己的父项驱动。
CurbedAnimation子类将一个Animation类(父亲),和几个Curve类(前向和反向曲线)作为输入,并且使用父亲的值作为曲线类的输入,以决定它们的输出。CurvedAnimation是不可变和无状态的。
ReverseAnimation子类将一个Animation类作为它的父亲,并翻转这个动画的值。它假设它的父亲使用的值介于0.0-1.0,并且再返回一个介于0.0-1.0的值。父亲动画的状态和方向也会被翻转。
ProxyAnimation子类将一个Animation作为它的父亲,并且只是转发父亲的状态和方向。然而,它的父亲是可变的。
TrainHoppingAnimation子类拥有两个父亲,并且在它们的值交叉时在两个父亲之间切换。

Animation Controllers

AnimationController是一个有状态的(stateful)Animation,它使用一个Ticker来驱动它运行。它可以被启动和停止。每次tick,它将自它启动以来已流逝的时间作为参数传递到一个Simulation模拟器中,以获取一个值,这个值就是它需要上报的值。如果模拟器在它已经终止时上报这个值,然后controller便会停止它自己。
可以给controller设置动画的下界和上界,以及一个持续时间。
在简单的场景中(使用forward(),reverse(),play()或者resume()),animation controller只是简单的在给定的时间段内做一个从下界到上界的线性插值(对于从相反的方向插值,也是这样)。
当使用repeat()方法,animation controller在给定的上下界之间重复地做线性插值。
当使用animateTo()方法并给定目标值和时长,animation controller会在给定的时长内从当前值到目标值之间做线性插值。如果没有指定时长,controller会使用默认时长和由controller的下界和上界指定的范围来确定动画的速率。
当使用fling(),会使用Force对象来创建一个专门的模拟器驱动controller运行。
当使用animateWith()方法,可以指定一个模拟器来驱动这个controller运行。
这些方法都最终返回由Ticker提供的future对象,这个future最终会当controller下次停止或者更改模拟器的时候解析。

将animatables Attach到animations

传递一个Animation(新的父亲)到Animatable的animate()方法,以创建一个新的Animation子类,这个子类表现的就像这个Animatable,但是是由它的父亲驱动的。