好的!延续前两篇《三天快速学习 Flutter(一)基础与布局》和《(二)事件》"从使用的角度出发,只学最核心、最常用" 的高效风格,第三篇聚焦 动画(Animation)。
太多教程繁琐、浪费时间。我们如果只从使用的角度出发,那么 Flutter 动画的学习曲线也可以大大缩短。记住这个公式:
布局解决能看到什么东西,事件决定能做什么事情,动画让布局和事件拥有更好的体验。
搞定这三样,就可以从事基本的开发了。本篇就带你用最短路径掌握 Flutter 动画的核心要点。
一、动画的本质:值的变化
在 Flutter 中,动画的本质不是直接操作 UI,而是驱动一个值(通常是 double 类型)随时间从一个状态平滑地变化到另一个状态。UI 组件监听这个值的变化,并据此重新绘制自己。
例如:
- 驱动
opacity(透明度)从1.0变为0.0,实现淡出效果。 - 驱动
width(宽度)从50.0变为200.0,实现伸展效果。 - 驱动
color(颜色)从红色变为蓝色,实现颜色渐变。
二、最核心的两个概念:Animation 和 AnimationController
要实现动画,离不开这两个基石:
-
AnimationController:动画的"总指挥"。- 它负责控制 动画的播放(
forward())、暂停、反向播放(reverse())和停止。 - 它内部持有一个从
0.0到1.0的值(称为value),代表动画的进度。 - 创建时需要传入一个
vsync参数(通常用this,即当前State对象),用于防止屏幕外的动画消耗不必要的资源。
- 它负责控制 动画的播放(
-
Animation:动画的"值提供者"。- 它本身不控制动画,而是包装
AnimationController的值,并可以对其应用插值器(Curves) 或类型转换。 - 最常用的
Animation是Tween(补间动画),它可以将0.0 - 1.0的范围映射到你想要的任何数值范围(如50.0 - 200.0)。
- 它本身不控制动画,而是包装
三、两种最常用、最简单的动画写法
1. 使用 AnimatedWidget (推荐新手)
这是最简洁的方式,它帮你自动处理了 StatefulWidget 的重建逻辑。
步骤:
- 在
State中创建AnimationController和Animation(如Tween)。 - 在
initState中初始化它们,并将Tween附加到Controller上。 - 使用
AnimatedContainer,AnimatedOpacity,AnimatedPadding等预置的AnimatedWidget,并将你的Animation对象赋给其属性。
示例:点击按钮,让一个容器的颜色和大小平滑变化。
class MyAnimatedWidget extends StatefulWidget {
@override
_MyAnimatedWidgetState createState() => _MyAnimatedWidgetState();
}
class _MyAnimatedWidgetState extends State<MyAnimatedWidget> with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _sizeAnimation;
late Animation<Color?> _colorAnimation;
@override
void initState() {
super.initState();
// 1. 创建控制器
_controller = AnimationController(
duration: const Duration(seconds: 1),
vsync: this,
);
// 2. 创建动画(Tween)
_sizeAnimation = Tween<double>(begin: 50.0, end: 200.0).animate(_controller);
_colorAnimation = ColorTween(begin: Colors.blue, end: Colors.red).animate(_controller);
}
@override
void dispose() {
_controller.dispose(); // 别忘了释放资源
super.dispose();
}
void _toggleAnimation() {
if (_controller.isCompleted) {
_controller.reverse(); // 如果动画完成,就倒放
} else {
_controller.forward(); // 否则正向播放
}
}
@override
Widget build(BuildContext context) {
return Column(
children: [
// 3. 使用 AnimatedContainer,它会自动监听动画值并重建
AnimatedContainer(
width: _sizeAnimation.value,
height: _sizeAnimation.value,
color: _colorAnimation.value,
duration: Duration.zero, // 因为我们用控制器控制,这里设为0
curve: Curves.easeIn, // 可以在这里或在 animate() 里加曲线
),
ElevatedButton(
onPressed: _toggleAnimation,
child: Text('开始/停止 动画'),
),
],
);
}
}
2. 使用 AnimatedBuilder
当你想对任意 的 Widget 添加动画,或者动画逻辑比较复杂时,AnimatedBuilder 是更灵活的选择。
核心思想: AnimatedBuilder 会监听你传给它的 Animation 对象,一旦值发生变化,就只重建它的 builder 函数返回的部分 ,而不是整个父 Widget,性能更好。
示例:让一个文本的字体大小随动画变化。
// ... (在 State 中同样需要 _controller 和 _sizeAnimation)
@override
Widget build(BuildContext context) {
return Column(
children: [
// 使用 AnimatedBuilder 包裹需要动画的部件
AnimatedBuilder(
animation: _sizeAnimation, // 监听这个动画
builder: (context, child) {
return Text(
'Hello, Flutter!',
style: TextStyle(fontSize: _sizeAnimation.value),
);
},
),
ElevatedButton(
onPressed: () {
_controller.forward(from: 0.0); // 从头开始播放
},
child: Text('放大文字'),
),
],
);
}
四、提升体验的关键:Curves(动画曲线)
默认的动画是线性匀速的,显得很机械。Curves 可以让你的动画拥有"生命感",比如先快后慢 (Curves.easeOut),或有弹性 (Curves.bounceInOut)。
使用方法: 在创建 Animation 时,通过 curve 参数指定。
_sizeAnimation = Tween<double>(begin: 50.0, end: 200.0)
.animate(CurvedAnimation(parent: _controller, curve: Curves.easeInOut));
五、总结:只需记住这几点
- 核心目标:动画就是让一个值平滑变化。
- 两大基石 :
AnimationController(控制播放) +Animation/Tween(定义值的范围)。 - 两种写法 :
- 简单场景用
AnimatedContainer、AnimatedOpacity等。 - 复杂或自定义场景用
AnimatedBuilder。
- 简单场景用
- 灵魂点缀 :用
Curves让动画更自然。 - 别忘清理 :在
dispose方法中调用_controller.dispose()。
搞定这些,你就已经掌握了 Flutter 动画 80% 的日常使用场景。剩下的,遇到具体需求再去查文档即可!