-
GIF 动图
-
Animation Framework package
-
Code-based Animation
- 隐式动画
- 显示动画
- CustomPainter
- 动画看起来是否像绘图?
- 是否想要用代码实现绘图动画?
- 使用标准原语是否容易实现动画?
- 代码实现是否困难?
- 使用代码实现动画是否有性能问题?
class AnimatedFoo extends ImplicitlyAnimatedWidget {}
- Align -> AnimatedAlign
- Container -> AnimatedContainer
- DefaultTextStyle -> AnimatedDefaultTextStyle
- Opacity -> AnimatedOpacity
- Padding -> AnimatedPadding
- PhysicalModel -> AnimatedPhysicalModel
- Positioned -> AnimatedPositioned
- PositionedDirectional -> AnimatedPositionedDirectional
- Theme -> AnimatedTheme
class FooTransition extends AnimatedWidget {}
- SizeTransition
- FadeTransition
- AlignTransition
- ScaleTransition
- SlideTransition
- RotationTransition
- PositionedTransition
- DecoratedBoxTransition
- DefaultTextStyleTransition
- RelativePositionedTransition
- AnimatedWidget
- AnimatedBuilder
Flutter 中的动画系统基于 Animation 对象的,widget 可以在 build 函数中读取 Animation 对象的当前值, 并且可以监听动画的状态改变。
abstract class Animation<T> extends Listenable implements ValueListenable<T> {}
-
Flutter 动画库中的一个核心类,它生成指导动画的值。
-
对象知道动画的当前状态(例如,它是开始、停止还是向前或向后移动),但它不知道屏幕上显示的内容。
Animation<double>
-
在 Flutter 中,Animation 对象本身和 UI 渲染没有任何关系。Animation 是一个抽象类,它拥有其当前值和状态(完成或停止)。其中一个比较常用的 Animation 类是 Animation。
-
Flutter 中的 Animation 对象是一个在一段时间内依次生成一个区间之间值的类。Animation 对象的输出可以是线性的、曲线的、一个步进函数或者任何其他可以设计的映射。 根据 Animation 对象的控制方式,动画可以反向运行,甚至可以在中间切换方向。
-
Animation 还可以生成除 double 之外的其他类型值,如:Animation 或 Animation。
-
Animation 对象有状态。可以通过访问其 value 属性获取动画的当前值。
CurvedAnimation
class CurvedAnimation extends Animation<double> with AnimationWithParentMixin<double> {}
-
将过程抽象为一个非线性曲线.
-
定义:https://api.flutter.dev/flutter/animation/Curves-class.html
自定义 Curve
class ShakeCurve extends Curve {
@override
double transform(double t) {
return math.sin(t * math.PI * 2);
}
}
AnimationController
class AnimationController extends Animation<double> ... {}
-
管理 Animation
-
AnimationController 是一个特殊的 Animation 对象,在屏幕刷新的每一帧,就会生成一个新的值。默认情况下,AnimationController 在给定的时间段内会线性的生成从 0.0 到 1.0 的数字。 例如,下面代码创建一个 Animation 对象,但不会启动它运行:
final AnimationController controller = new AnimationController(
duration: const Duration(milliseconds: 2000), vsync: this);
-
AnimationController 派生自 Animation,因此可以在需要 Animation 对象的任何地方使用。 但是,AnimationController 具有控制动画的其他方法。例如,.forward()方法可以启动动画。数字的产生与屏幕刷新有关,因此每秒钟通常会产生 60 个数字,在生成每个数字后,每个 Animation 对象调用添加的 Listener 对象。
-
当创建一个 AnimationController 时,需要传递一个 vsync 参数,存在 vsync 时会防止屏幕外动画(译者语:动画的 UI 不在当前屏幕时)消耗不必要的资源。 通过将 SingleTickerProviderStateMixin 添加到类定义中,可以将 stateful 对象作为 vsync 的值。
-
vsync 对象会绑定动画的定时器到一个可视的 widget,所以当 widget 不显示时,动画定时器将会暂停,当 widget 再次显示时,动画定时器重新恢复执行,这样就可以避免动画相关 UI 不在当前屏幕时消耗资源。 如果要使用自定义的 State 对象作为 vsync 时,请包含 TickerProviderStateMixin。
注意: 在某些情况下,值(position,值动画的当前值)可能会超出 AnimationController 的 0.0-1.0 的范围。例如,fling()函数允许您提供速度(velocity)、力量(force)、position(通过 Force 对象)。位置(position)可以是任何东西,因此可以在 0.0 到 1.0 范围之外。 CurvedAnimation 生成的值也可以超出 0.0 到 1.0 的范围。根据选择的曲线,CurvedAnimation 的输出可以具有比输入更大的范围。例如,Curves.elasticIn 等弹性曲线会生成大于或小于默认范围的值。
- 在正在执行动画的对象所使用的数据范围之间生成值。例如,Tween 可能会生成从红到蓝之间的色值,或者从 0 到 255。
class Tween<T extends dynamic> extends Animatable<T> {}
- 默认情况下,AnimationController 对象的范围从 0.0 到 1.0。如果您需要不同的范围或不同的数据类型,则可以使用 Tween 来配置动画以生成不同的范围或数据类型的值。例如,以下示例,Tween 生成从-200.0 到 0.0 的值:
final Tween doubleTween = new Tween<double>(begin: -200.0, end: 0.0);
-
Tween 是一个无状态(stateless)对象,需要 begin 和 end 值。Tween 的唯一职责就是定义从输入范围到输出范围的映射。输入范围通常为 0.0 到 1.0,但这不是必须的。
-
Tween 继承自 Animatable,而不是继承自 Animation。Animatable 与 Animation 相似,不是必须输出 double 值。例如,ColorTween 指定两种颜色之间的过渡。
final Tween colorTween =
new ColorTween(begin: Colors.transparent, end: Colors.black54);
- Tween 对象不存储任何状态。相反,它提供了 evaluate(Animation animation)方法将映射函数应用于动画当前值。 Animation 对象的当前值可以通过 value()方法取到。evaluate 函数还执行一些其它处理,例如分别确保在动画值为 0.0 和 1.0 时返回开始和结束状态。
Tween.animate
- 要使用 Tween 对象,请调用其 animate()方法,传入一个控制器对象。例如,以下代码在 500 毫秒内生成从 0 到 255 的整数值。
final AnimationController controller = new AnimationController(
duration: const Duration(milliseconds: 500), vsync: this);
Animation<int> alpha = new IntTween(begin: 0, end: 255).animate(controller);
注意 animate()返回的是一个 Animation,而不是一个 Animatable。
- 以下示例构建了一个控制器、一条曲线和一个 Tween:
final AnimationController controller = new AnimationController(
duration: const Duration(milliseconds: 500), vsync: this);
final Animation curve =
new CurvedAnimation(parent: controller, curve: Curves.easeOut);
Animation<int> alpha = new IntTween(begin: 0, end: 255).animate(curve);
动画通知
- 一个 Animation 对象可以拥有 Listeners 和 StatusListeners 监听器,可以用 addListener()和 addStatusListener()来添加。 只要动画的值发生变化,就会调用监听器。一个 Listener 最常见的行为是调用 setState()来触发 UI 重建。动画开始、结束、向前移动或向后移动(如 AnimationStatus 所定义)时会调用 StatusListener。
监视动画的过程
-
使用 addStatusListener 来处理动画状态更改的通知,例如启动、停止或反转方向。
-
当动画完成或返回其开始状态时,通过反转方向来无限循环运行动画
知道动画何时改变状态通常很有用的,如完成、前进或倒退。你可以通过 addStatusListener()来得到这个通知。 以下代码修改 animate1 示例,以便它监听动态状态更改并打印更新。 下面高亮显示的部分为修改的:
class _LogoAppState extends State<LogoApp> with SingleTickerProviderStateMixin {
AnimationController controller;
Animation<double> animation;
initState() {
super.initState();
controller = new AnimationController(
duration: const Duration(milliseconds: 2000), vsync: this);
animation = new Tween(begin: 0.0, end: 300.0).animate(controller)
..addStatusListener((state) => print("$state"));
controller.forward();
}
//...
}
运行此代码将输出以下内容:
AnimationStatus.forward
AnimationStatus.completed
用 AnimatedWidget 简化
-
使用 AnimatedWidget 创建一个可重用动画的 widget。
-
Flutter API 提供的关于 AnimatedWidget 的示例包括:AnimatedBuilder、AnimatedModalBarrier、DecoratedBoxTransition、FadeTransition、PositionedTransition、RelativePositionedTransition、RotationTransition、ScaleTransition、SizeTransition、SlideTransition。
-
AnimatedWidget 类允许您从 setState()调用中的动画代码中分离出 widget 代码。AnimatedWidget 不需要维护一个 State 对象来保存动画。
用AnimatedBuilder重构
-
主要作用是职责分离:
- 显示 logo
- 定义 Animation 对象
- 渲染过渡效果
-
Flutter API 中 AnimatedBuilder 的示例包括: BottomSheet、ExpansionTile、 PopupMenu、ProgressIndicator、RefreshIndicator、Scaffold、SnackBar、TabBar、TextField。
并行动画
注意:此示例展示了如何在同一个动画控制器上使用多个 Tween,其中每个 Tween 管理动画中的不同效果。 本示例仅用于示例,如果您在生产代码中需要使用不透明度和大小变化的 Tween,则可能会使用 FadeTransition 和 SizeTransition。
final AnimationController controller =
new AnimationController(duration: const Duration(milliseconds: 2000), vsync: this);
final Animation<double> sizeAnimation =
new Tween(begin: 0.0, end: 300.0).animate(controller);
final Animation<double> opacityAnimation =
new Tween(begin: 0.1, end: 1.0).animate(controller);
-
你可以通过 sizeAnimation.value 来获取大小,通过 opacityAnimation.value 来获取不透明度,但 AnimatedWidget 的构造函数只接受一个动画对象。 为了解决这个问题,该示例创建了自己的 Tween 对象并显式计算了这些值。
-
其 build 方法.evaluate()在父级的动画对象上调用 Tween 函数以计算所需的 size 和 opacity 值。
-
交错动画由一个动画序列或重叠的动画组成。
-
要创建交错动画,需要使用多个动画对象。
-
一个 AnimationController 控制所有动画。
-
每个动画对象在间隔(Interval)期间指定动画。
-
对于要执行动画的每个属性都要创建一个 Tween。
引用