五、Flutter动画
目录
- 1. Flutter 中动画的基本概念是什么?
- 2. 解释 AnimationController 和 Tween 的作用
- 3. 如何实现一个补间(Tween)动画?
- 4. 什么是隐式动画?举例说明
- 5. 如何实现自定义复杂动画?
1. Flutter 中动画的基本概念是什么?
在 Flutter 中,动画是通过在一段时间内连续改变属性值来实现的视觉效果变化。核心概念包括:
概念 | 说明 |
---|---|
动画值 | 随时间变化的数值(通常是 0.0 → 1.0) |
动画控制器 | 管理动画的播放、停止、反转等操作 |
补间 (Tween) | 定义起始值和结束值之间的过渡(如位置、大小、颜色等) |
动画曲线 | 控制动画变化速率(如加速、减速、弹跳等) |
动画监听器 | 在动画值变化时更新 UI |
动画状态 | 运行中 (forward)、完成 (completed)、反转中 (reverse)、停止 (dismissed) |
动画分类:
- 隐式动画:自动处理的简单动画(如
AnimatedContainer
) - 显式动画:需要手动控制的复杂动画(使用
AnimationController
)
2. 解释 AnimationController 和 Tween 的作用
AnimationController
- 作用:管理动画的播放状态和持续时间
- 特点:
- 需要
TickerProvide*
(如SingleTickerProviderStateMixin
) - 默认输出 0.0 → 1.0 的值
- 控制动画播放 (
forward()
)、停止 (stop()
)、反转 (reverse()
)
- 需要
- 创建:
late AnimationController _controller;
void initState() {super.initState();_controller = AnimationController(duration: const Duration(seconds: 2), // 动画时长vsync: this, // 使用 TickerProvider);
}
Tween
- 作用:定义动画的值范围(如颜色、大小、位置等)
- 特点:
- 将 0.0→1.0 映射到实际值范围
- 支持多种数据类型(
ColorTwee*
,SizeTween
等)
- 使用:
final Animation<double> _sizeAnim = Tween<double>(begin: 50.0, end: 200.0,
).animate(_controller);
3. 如何实现一个补间(Tween)动画?
步骤:
- 创建
AnimationController
- 定义
Tween
并绑定控制器 - 添加监听器重建 UI
- 启动动画
示例代码:
class TweenAnimationDemo extends StatefulWidget { _TweenAnimationDemoState createState() => _TweenAnimationDemoState();
}class _TweenAnimationDemoState extends State<TweenAnimationDemo> with SingleTickerProviderStateMixin {late AnimationController _controller;late Animation<double> _sizeAnim;late Animation<Color?> _colorAnim;void initState() {super.initState();// 1. 创建控制器_controller = AnimationController(duration: const Duration(seconds: 2),vsync: this,)..repeat(reverse: true); // 循环播放// 2. 创建补间动画_sizeAnim = Tween<double>(begin: 50, end: 200).animate(_controller);_colorAnim = ColorTween(begin: Colors.blue, end: Colors.red).animate(_controller);} Widget build(BuildContext context) {// 3. 使用 AnimatedBuilder 优化性能return AnimatedBuilder(animation: _controller,builder: (context, child) {return Center(child: Container(width: _sizeAnim.value,height: _sizeAnim.value,color: _colorAnim.value,),);},);}void dispose() {_controller.dispose(); // 释放资源super.dispose();}
}
4. 什么是隐式动画?举例说明
隐式动画:只需设置目标值,Flutter 自动处理动画过程的简化动画。
特点:
- 无需管理
AnimationController
- 内置 300ms 默认动画时长
- 通过
setState()
改变属性值自动触发
常用隐式动画组件:
组件 | 作用 |
---|---|
AnimatedContainer | 容器属性变化(大小/颜色等) |
AnimatedOpacity | 透明度变化 |
AnimatedPositioned | 位置变化(Stack 内) |
AnimatedAlign | 对齐方式变化 |
示例:点击改变容器大小和颜色
class ImplicitAnimationDemo extends StatefulWidget { _ImplicitAnimationDemoState createState() => _ImplicitAnimationDemoState();
}class _ImplicitAnimationDemoState extends State<ImplicitAnimationDemo> {double _size = 100;Color _color = Colors.blue;void _animate() {setState(() {_size = _size == 100 ? 200 : 100;_color = _color == Colors.blue ? Colors.green : Colors.blue;});} Widget build(BuildContext context) {return GestureDetector(onTap: _animate,child: AnimatedContainer(duration: Duration(seconds: 1), // 动画时长width: _size,height: _size,color: _color,curve: Curves.easeInOut, // 动画曲线child: Center(child: Text('点击我')),),);}
}
5. 如何实现自定义复杂动画?
对于复杂动画(如路径动画、物理动画、多动画同步),推荐使用:
1. 组合多个动画
late Animation<double> _sizeAnim;
late Animation<double> _rotationAnim;
void initState() {super.initState();_sizeAnim = Tween(begin: 0.0, end: 1.0).animate(CurvedAnimation(parent: _controller,curve: Interval(0.0, 0.5), // 只在前半段执行),);_rotationAnim = Tween(begin: 0.0, end: 2 * pi).animate(CurvedAnimation(parent: _controller,curve: Interval(0.5, 1.0), // 只在后半段执行),);
}
2. 使用物理动画(SpringSimulation)
void _runSpringAnimation() {final spring = SpringSimulation(SpringDescription(mass: 1, stiffness: 100, damping: 10),0.0, // 起始位置300.0, // 目标位置10.0, // 初始速度);_controller.animateWith(spring);
}
3. 自定义动画曲线
final customCurve = CurveTween(curve: Curves.easeInOutBack,
);_animation = customCurve.animate(_controller);
4. 使用动画状态机
_controller.addStatusListener((status) {if (status == AnimationStatus.completed) {_controller.reverse();} else if (status == AnimationStatus.dismissed) {_controller.forward();}
});
完整示例:弹跳球效果
class BouncingBallDemo extends StatefulWidget { _BouncingBallDemoState createState() => _BouncingBallDemoState();
}class _BouncingBallDemoState extends State<BouncingBallDemo>with SingleTickerProviderStateMixin {late AnimationController _controller;late Animation<double> _bounceAnim;void initState() {super.initState();_controller = AnimationController(duration: const Duration(seconds: 2),vsync: this,)..repeat(reverse: true);// 使用弹性曲线模拟弹跳_bounceAnim = Tween<double>(begin: 0, end: 300).animate(CurvedAnimation(parent: _controller,curve: Curves.elasticOut, // 弹性效果),);} Widget build(BuildContext context) {return AnimatedBuilder(animation: _controller,builder: (context, child) {return Stack(children: [Positioned(bottom: _bounceAnim.value,left: MediaQuery.of(context).size.width / 2 - 25,child: Container(width: 50,height: 50,decoration: BoxDecoration(color: Colors.red,shape: BoxShape.circle,),),),],);},);}
}