本教程向您展示如何在Flutter中构建显式动画。在介绍了动画库中的一些基本概念、类和方法之后,它将带您浏览5个动画示例。这些示例相互构建,向您介绍动画库的不同方面。
Flutter SDK还提供了过渡动画,比如FadeTransition
、SizeTransition
和SlideTransition
。这些简单的动画通过设置起点和终点来触发。它们比这里描述的显式动画更容易实现。
Flutter中的动画系统是基于类型化的动画对象。微件(widget)可以通过读取它们的当前值并侦听它们的状态变化,直接将这些动画合并到它们的构建函数中,也可以使用这些动画作为传递给其他微件的更精细动画的基础。
在Flutter中,动画对象对屏幕上的内容一无所知。Animation
是一个抽象类,它理解当前值及其状态(完成或取消)。比较常用的动画类型之一是Animation
。
Animation
对象在一定的持续时间内连续地在两个值之间生成插值数。Animation
对象的输出可以是线性的、曲线的、阶跃函数的,或者您可以设计的任何其他映射。根据Animation
对象的控制方式,它可以反向运行,甚至在中间切换方向。
动画还可以插入除double
之外的类型,比如Animation
或Animation
。
Animation
对象具有状态。它的当前值始终在.value
成员中可用。
Animation
对象对呈现或build()
函数一无所知。
CurvedAnimation
将动画的进度定义为非线性曲线。
animation = CurvedAnimation(parent: controller, curve: Curves.easeIn);
注意:
Curves
类定义了许多常用的曲线,或者您可以创建自己的曲线。例如:import 'dart:math'; class ShakeCurve extends Curve { @override double transform(double t) => sin(t * pi * 2); }
CurvedAnimation
和AnimationController
(在下一节中描述)都是Animation
的子类,因此可以互换传递它们。CurvedAnimation
封装了它正在修改的对象——你不需要子类化AnimationController
来实现曲线。
AnimationController
是一个特殊的Animation
对象,每当硬件准备好创建一个新帧时,它都会生成一个新值。默认情况下,AnimationController
在给定的持续时间内线性生成0.0到1.0之间的数字。例如,这段代码创建了一个动画对象,但是没有让它运行:
controller =
AnimationController(duration: const Duration(seconds: 2), vsync: this);
AnimationControlle
r派生自Animation
,因此它可以用于任何需要动画对象的地方。然而,AnimationController
有额外的方法来控制动画。例如,使用.forward()
方法启动动画。生成数字与屏幕刷新相关联,因此通常每秒生成60个数字。在生成每个数字之后,每个动画对象都会调用附加的侦听器对象。要为每个子元素创建自定义显示列表,请参见RepaintBoundary
。
在创建AnimationController
时,要传递一个vsync
参数。vsync
的存在可以防止屏幕外动画消耗不必要的资源。通过在类定义中添加SingleTickerProviderStateMixin
,您可以使用您的有状态对象作为vsync
。你可以在GitHub上的animate1中看到这样一个例子。
注意:
在某些情况下,位置可能会超过AnimationController
的0-1.0范围。例如,fling()
函数 允许您提供速度、力和位置(通过Force
对象)。该位置可以是0.0到1.0范围之外的任何位置。
即使
AnimationController
没有,CurvedAnimation
动画也可以超过0.0到1.0的范围。根据所选择的曲线,CurvedAnimation
的输出可以比输入具有更大的范围。例如,弹性曲线Curves
。elasticIn
将明显超过或低于默认范围。
默认情况下,AnimationController
对象的范围从0.0到1.0。如果需要不同的范围或不同的数据类型,可以使用Tween
来配置动画,以插入到不同的范围或数据类型。例如,下面的Tween
从-200.0到0.0:
tween = Tween(begin: -200, end: 0);
Tween
是一个无状态对象,只接受begin
和end
。Tween
的唯一工作是定义一个从输入范围到输出范围的映射。输入范围通常是0.0到1.0,但这不是必需的。
Tween
继承自Animatable
,而不是Animation
。像Animation一样
,Animatable
不需要输出double
。例如,ColorTween
指定了两种颜色之间的进程。
colorTween = ColorTween(begin: Colors.transparent, end: Colors.black54);
Tween
对象不存储任何状态。相反,它提供了evaluate(Animation
方法,该方法将映射函数应用于动画的当前值。Animation
对象的当前值可以在.value
方法中找到。evaluate
函数还执行一些内务管理,比如确保在动画值分别为0.0和1.0时返回begin
和end
。
要使用Tween
对象,在Tween
上调用animate()
,传入控制器对象。例如,下面的代码在500毫秒的时间内生成从0到255的整数值。
AnimationController controller = AnimationController(
duration: const Duration(milliseconds: 500), vsync: this);
Animation alpha = IntTween(begin: 0, end: 255).animate(controller);
注意:
animate()
方法返回Animation
对象而不是Animatable
对象。
下面的例子展示了一个controller
, 一个 curve
, 和一个Tween
:
AnimationController controller = AnimationController(
duration: const Duration(milliseconds: 500), vsync: this);
final Animation curve =
CurvedAnimation(parent: controller, curve: Curves.easeOut);
Animation alpha = IntTween(begin: 0, end: 255).animate(curve);
Animation
对象可以有侦听器和状态侦听器,它们由addListener()
和addStatusListener()
定义。每当动画的值发生变化时,就会调用侦听器。侦听器最常见的行为是调用setState()
来重新构建。当动画开始、结束、向前移动或向后移动(由AnimationStatus
定义)时,将调用StatusListener
。下一节有一个addListener()
方法的例子,监视动画的进度显示了一个addStatusListener()
的例子。