动画简介
精心设计的动画让 UI 感觉更直观,有助于打造精致应用的流畅外观和感觉,并改善用户体验。Flutter 的动画支持使得实现各种动画类型变得容易。许多小部件,特别是Material 小部件,都附带了其设计规范中定义的标准运动效果,但也可以自定义这些效果。
选择一种方法
#在 Flutter 中创建动画时,可以采用不同的方法。哪种方法适合你?为了帮助你做出决定,请观看视频《如何选择适合你的 Flutter 动画小部件?》(也作为一篇配套文章发布。)
(要深入了解决策过程,请观看 Flutter Europe 上发布的视频《正确使用 Flutter 动画》。)
如视频所示,以下决策树可帮助您决定在实现 Flutter 动画时采用哪种方法。

动画深入解析
#要更深入地了解 Flutter 动画的工作原理,请观看动画深入解析。(也作为配套文章发布。)
隐式和显式动画
#预封装的隐式动画
#如果预封装的隐式动画(最容易实现的动画)符合您的需求,请观看隐式动画基础知识。(也作为配套文章发布。)
自定义隐式动画
#要创建自定义隐式动画,请观看使用 TweenAnimationBuilder 创建您自己的自定义隐式动画。(也作为配套文章发布。)
内置隐式动画
#要创建显式动画(您控制动画,而不是让框架控制它),也许可以使用内置的显式动画类之一。欲了解更多信息,请观看使用内置显式动画制作您的第一个定向动画。(也作为配套文章发布。)
显式动画
#如果您需要从头开始构建显式动画,请观看使用 AnimatedBuilder 和 AnimatedWidget 创建自定义显式动画。(也作为配套文章发布。)
在新标签页中观看 YouTube 视频:“使用 AnimatedBuilder 和 AnimatedWidget 创建自定义显式动画”
动画类型
#通常,动画要么是补间动画,要么是基于物理的动画。以下部分解释了这些术语的含义,并为您提供了可以了解更多信息的资源。
补间动画
#“补间”是“in-betweening”的缩写。在补间动画中,定义了起始点和结束点,以及时间线和定义过渡时序和速度的曲线。框架计算如何从起始点过渡到结束点。
请参阅动画教程,其中示例使用了补间动画。
另请参阅
Tween
、CurveTween
和TweenSequence
的 API 文档。
基于物理的动画
#在基于物理的动画中,运动被模拟成类似于真实世界的行为。例如,当你抛出一个球时,它在哪里以及何时落地取决于抛球的速度以及它离地面的距离。同样,一个系在弹簧上的球落地(并弹跳)的方式与一个系在绳子上的球落地的方式不同。
使用物理模拟来为组件添加动画
Flutter 开发指南动画部分的一个配方。另请参阅
AnimationController.animateWith
和SpringSimulation
的 API 文档。
常见动画模式
#大多数 UX 或动效设计师发现,在设计 UI 时,某些动画模式被重复使用。本节列出了一些常用的动画模式,并告诉您在哪里可以学到更多。
动画列表或网格
#这种模式涉及对列表中或网格中元素的添加或删除进行动画处理。
AnimatedList
示例
此演示来自 示例应用目录,展示了如何动画添加元素到列表或移除选定元素。当用户使用加号 (+) 和减号 (-) 按钮修改列表时,内部 Dart 列表会同步。
共享元素过渡
#在此模式中,用户从页面中选择一个元素(通常是图像),然后 UI 将选定的元素动画到包含更多详细信息的新页面。在 Flutter 中,您可以使用 `Hero` 小部件轻松实现路由(页面)之间的共享元素过渡。
英雄动画 如何创建两种风格的英雄动画
- 英雄在改变位置和大小的同时从一个页面飞向另一个页面。
- 英雄的边界在从一个页面飞向另一个页面时,从圆形变为方形。
交错动画
#动画被分解成更小的动作,其中一些动作被延迟。这些较小的动画可能是顺序的,也可能部分或完全重叠。
基本动画概念和类
#Flutter 中的动画系统基于类型化的 Animation
对象。小部件可以直接在它们的 build 函数中通过读取其当前值并监听其状态变化来整合这些动画,或者它们可以使用这些动画作为更精细动画的基础,然后将这些动画传递给其他小部件。
Animation<double>
#在 Flutter 中,一个 Animation
对象对屏幕上显示的内容一无所知。Animation
是一个抽象类,它了解其当前值和状态(已完成或已取消)。最常用的动画类型之一是 Animation<double>
。
一个 Animation
对象在特定持续时间内按顺序生成两个值之间的插值数字。Animation
对象的输出可以是线性的、曲线的、阶梯函数或您可以创建的任何其他映射。根据 Animation
对象的控制方式,它可以反向运行,甚至在中间切换方向。
动画也可以插值除了 double 之外的其他类型,例如 Animation<Color>
或 Animation<Size>
。
一个 Animation
对象拥有状态。它的当前值始终在 .value
成员中可用。
Animation
对象对渲染或 build()
函数一无所知。
CurvedAnimation
#CurvedAnimation
将动画进度定义为非线性曲线。
animation = CurvedAnimation(parent: controller, curve: Curves.easeIn);
CurvedAnimation
和 AnimationController
(在接下来的章节中描述)都属于 Animation<double>
类型,因此它们可以互换使用。CurvedAnimation
包装它正在修改的对象——你不需要通过子类化 AnimationController
来实现曲线。
您可以将 Curves
与 CurvedAnimation
配合使用。Curves
类定义了许多常用的曲线,或者您可以创建自己的曲线。例如:
import 'dart:math';
class ShakeCurve extends Curve {
@override
double transform(double t) => sin(t * pi * 2);
}
如果你想将动画曲线应用于 Tween
,请考虑使用 CurveTween
。
AnimationController
#AnimationController
是一个特殊的 Animation
对象,每当硬件准备好新帧时,它就会生成一个新值。默认情况下,AnimationController
在给定持续时间内线性地生成从 0.0 到 1.0 的数字。例如,此代码创建一个 Animation
对象,但不会启动它运行:
controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
);
AnimationController
派生自 Animation<double>
,因此可以在需要 Animation
对象的地方使用它。但是,AnimationController
具有控制动画的附加方法。例如,您可以使用 .forward()
方法启动动画。数字的生成与屏幕刷新相关联,因此通常每秒生成 60 个数字。生成每个数字后,每个 Animation
对象都会调用附加的 Listener
对象。要为每个子项创建自定义显示列表,请参阅 RepaintBoundary
。
创建 AnimationController
时,您会为其传递一个 vsync
参数。vsync
的存在可以防止屏幕外动画消耗不必要的资源。您可以通过将 SingleTickerProviderStateMixin
添加到类定义中,将您的有状态对象用作 vsync。您可以在 GitHub 上的 animate1 中看到一个示例。
Tween
#默认情况下,AnimationController
对象的范围从 0.0 到 1.0。如果您需要不同的范围或不同的数据类型,可以使用 Tween
来配置动画以插值到不同的范围或数据类型。例如,下面的 Tween
从 -200.0 到 0.0:
tween = Tween<double>(begin: -200, end: 0);
Tween
是一个无状态对象,只接受 begin
和 end
。Tween
的唯一作用是定义从输入范围到输出范围的映射。输入范围通常是 0.0 到 1.0,但这并非强制要求。
一个 Tween
继承自 Animatable<T>
,而不是 Animation<T>
。一个 Animatable
,像 Animation
一样,不一定输出 double。例如,ColorTween
指定了两种颜色之间的渐变。
colorTween = ColorTween(begin: Colors.transparent, end: Colors.black54);
Tween
对象不存储任何状态。相反,它提供了 evaluate(Animation<double> animation)
方法,该方法使用 transform
函数将动画的当前值(介于 0.0 和 1.0 之间)映射到实际的动画值。
Animation
对象的当前值可以在 .value
方法中找到。evaluate 函数还执行一些内务管理,例如确保当动画值分别为 0.0 和 1.0 时返回 begin 和 end。
Tween.animate
#要使用 Tween
对象,请在 Tween
上调用 animate()
,并传入控制器对象。例如,以下代码在 500 毫秒内生成从 0 到 255 的整数值。
AnimationController controller = AnimationController(
duration: const Duration(milliseconds: 500),
vsync: this,
);
Animation<int> alpha = IntTween(begin: 0, end: 255).animate(controller);
以下示例展示了一个控制器、一条曲线和一个 Tween
:
AnimationController controller = AnimationController(
duration: const Duration(milliseconds: 500),
vsync: this,
);
final Animation<double> curve = CurvedAnimation(
parent: controller,
curve: Curves.easeOut,
);
Animation<int> alpha = IntTween(begin: 0, end: 255).animate(curve);
动画通知
#一个 Animation
对象可以有 Listener
s 和 StatusListener
s,通过 addListener()
和 addStatusListener()
定义。当动画的值改变时,就会调用 Listener
。Listener
最常见的行为是调用 setState()
来触发重建。当动画开始、结束、向前或向后移动时,就会调用 StatusListener
,这由 AnimationStatus
定义。
代码实验室、教程和文章
#以下资源是学习 Flutter 动画框架的良好起点。每个文档都展示了如何编写动画代码。
隐式动画代码实验室
通过分步说明和交互式示例,涵盖如何使用隐式动画。动画教程
解释了 Flutter 动画包中的基本类(控制器、Animatable
、曲线、监听器、构建器),并指导您逐步完成使用动画 API 不同方面的补间动画。本教程展示了如何创建您自己的自定义显式动画。Flutter 从零到一,第一部分 和 第二部分
Medium 文章,展示了如何使用补间动画创建动画图表。休闲游戏工具包
一个包含游戏模板的工具包,其中包含如何使用 Flutter 动画的示例。
其他资源
#请通过以下链接了解更多 Flutter 动画知识