前言
在上一篇文章中,我们用 StatefulWidget 和 setState 让 Birdle 游戏真正能玩起来了------玩家输入猜测、按回车、棋盘实时更新颜色。但你可能注意到,颜色的变化是"啪"一下瞬间切换的,没有任何过渡效果,显得有点生硬。
今天这篇文章基于官方教程的「Implicit Animations」章节,我们将用 Flutter 最简单的动画方式------隐式动画 ,给方块的颜色变化添加平滑的过渡效果。最神奇的是,你只需要改两行代码就能实现。
这也是 Birdle 系列教程的最后一课,完成后你就拥有了一个完整的猜词游戏!
一、什么是隐式动画?
Flutter 的动画 API 非常丰富,但最简单的入门方式就是隐式动画(Implicit Animations)。
所谓"隐式",就是你不需要手动管理动画的中间过程。你只需要告诉 Flutter"我要从 A 变到 B",它会自动帮你处理从 A 到 B 之间的每一帧过渡。
打个比方:显式动画就像手动翻书做动画,每一帧都要自己画。隐式动画就像跟导航说"我要去北京",导航自动帮你规划路线------你只管说目的地,过程它全搞定。
Flutter 提供了一系列 Animated 开头的隐式动画组件,其中最常用的就是 AnimatedContainer。
二、从 Container 到 AnimatedContainer
2.1 当前的问题
回顾一下我们 Tile 组件中的 Container:
less
// 当前写法:颜色变化是瞬间切换的
return Container(
width: 60,
height: 60,
decoration: BoxDecoration(
border: Border.all(color: Colors.grey.shade300),
color: switch (hitType) {
HitType.hit => Colors.green, // 瞬间变绿
HitType.partial => Colors.yellow, // 瞬间变黄
HitType.miss => Colors.grey, // 瞬间变灰
_ => Colors.white,
},
),
// ...
);
当 hitType 从 none 变成 hit 时,背景色从白色"啪"地一下跳到绿色,没有任何中间过渡。
2.2 替换为 AnimatedContainer
修复方法极其简单------把 Container 换成 AnimatedContainer,再加一个 duration 属性:
less
// 改动后:颜色变化有平滑的过渡动画
return AnimatedContainer(
// ===== 新增:动画持续时间 =====
// Duration(milliseconds: 500) 表示动画用 500 毫秒(0.5 秒)完成
// 颜色会在这段时间内从旧值平滑过渡到新值
duration: Duration(milliseconds: 500),
width: 60,
height: 60,
decoration: BoxDecoration(
border: Border.all(color: Colors.grey.shade300),
color: switch (hitType) {
HitType.hit => Colors.green, // 0.5 秒平滑过渡到绿色
HitType.partial => Colors.yellow, // 0.5 秒平滑过渡到黄色
HitType.miss => Colors.grey, // 0.5 秒平滑过渡到灰色
_ => Colors.white,
},
),
// ...
);
就这样!只改了两处:Container → AnimatedContainer,加了 duration 属性。现在当玩家提交猜测时,每个方块的颜色会用半秒时间平滑过渡,而不是瞬间跳变。
2.3 AnimatedContainer 能动画化哪些属性?
不只是颜色,AnimatedContainer 可以自动动画化以下所有属性的变化:
color/decoration(颜色、背景、边框、阴影)width/height(宽高)padding/margin(内外边距)alignment(对齐方式)transform(变换,如旋转、缩放)
只要属性值发生了变化,AnimatedContainer 都会自动创建从旧值到新值的平滑过渡。
三、用 Curve 自定义动画节奏
3.1 什么是 Curve?
默认情况下,动画是匀速进行的(线性动画)。但现实中,很多运动并不是匀速的------球落地会弹跳,车启动会先慢后快。Curve(曲线)就是用来控制动画在不同时间点的速度的。
3.2 添加 Curve
给 AnimatedContainer 添加 curve 属性:
less
return AnimatedContainer(
duration: Duration(milliseconds: 500),
// ===== 新增:动画曲线 =====
// Curves.easeIn → 先慢后快,像汽车起步加速
curve: Curves.easeIn,
width: 60,
height: 60,
// ... 其余代码不变
);
3.3 常用 Curve 对比
| Curve | 效果 | 适用场景 |
|---|---|---|
Curves.linear |
匀速(默认) | 进度条、计时器 |
Curves.easeIn |
先慢后快 | 元素进入画面 |
Curves.easeOut |
先快后慢 | 元素减速停下 |
Curves.easeInOut |
先慢→加速→再减慢 | 大多数通用动画 |
Curves.bounceIn |
弹跳进入 | 游戏、趣味效果 |
Curves.bounceOut |
弹跳结束 | 按钮反馈、掉落效果 |
Curves.elasticIn |
弹性拉伸进入 | 拉弓效果 |
Curves.decelerate |
持续减速 | 自然减速停下 |
你可以随意尝试不同的曲线,找到最适合你应用的效果。对于 Birdle 游戏,Curves.easeIn 或 Curves.easeInOut 都是不错的选择。
四、其他常用的隐式动画组件
AnimatedContainer 只是 Flutter 隐式动画家族的一员。以下是其他常用的隐式动画组件:
less
// AnimatedOpacity:平滑地改变透明度
// 比如让一个组件淡入淡出
AnimatedOpacity(
opacity: isVisible ? 1.0 : 0.0, // 从完全透明到完全不透明
duration: Duration(milliseconds: 300),
child: Text('我会淡入淡出'),
)
// AnimatedPadding:平滑地改变内边距
// 比如点击后让内容"缩进"
AnimatedPadding(
padding: isExpanded
? EdgeInsets.all(20.0) // 展开时边距大
: EdgeInsets.all(4.0), // 收起时边距小
duration: Duration(milliseconds: 200),
child: Text('我的边距会动画变化'),
)
// AnimatedAlign:平滑地改变对齐方式
// 比如让一个组件从左边滑到右边
AnimatedAlign(
alignment: isLeft
? Alignment.centerLeft // 靠左
: Alignment.centerRight, // 靠右
duration: Duration(milliseconds: 400),
child: Icon(Icons.star),
)
它们的使用方式都一样:替换对应的非动画组件,加上 duration,搞定。
五、本节知识点小结
隐式动画: Flutter 中最简单的动画方式。你只需指定目标状态,组件自动处理中间过渡。以 Animated 开头的组件都是隐式动画组件。
AnimatedContainer: Container 的动画版本。将 Container 替换为 AnimatedContainer 并添加 duration 属性,所有可动画化的属性(颜色、大小、边距等)变化时都会自动产生平滑过渡。
duration: 控制动画从旧值到新值需要多长时间。Duration(milliseconds: 500) 表示 0.5 秒。
curve: 控制动画在不同时间点的速度变化。默认是匀速(linear),可以改为 easeIn、bounceOut 等创造不同的动画感觉。
六、Birdle 系列回顾
恭喜你!到这里,Birdle 猜词游戏的全部 UI 教程就完成了。让我们回顾一下这个系列的学习历程:
| 篇目 | 主题 | 核心收获 |
|---|---|---|
| 第 1 篇 | 环境搭建 | 安装 Git、VS Code、Flutter SDK |
| 第 2 篇 | 创建应用 | runApp、Widget 树、热重载 |
| 第 3 篇 | Widget 基础 | 自定义 StatelessWidget、构造函数传参、BoxDecoration |
| 第 4 篇 | 布局入门 | Scaffold、AppBar、Column、Row、集合 for 语法 |
| 第 5 篇 | DevTools | Widget Inspector、Property Editor、无界约束 |
| 第 6 篇 | 用户输入 | TextField、TextEditingController、FocusNode、回调函数 |
| 第 7 篇 | StatefulWidget | State、setState、界面响应数据变化 |
| 第 8 篇 | 隐式动画 | AnimatedContainer、duration、curve |
从零开始,你已经掌握了构建 Flutter 应用的核心基础。接下来的官方教程会进入状态管理的进阶章节(HTTP 请求、ChangeNotifier 等),带你构建更复杂的应用。
继续加油,未来的 Flutter 开发者!