目录
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,
),
),
),
],
);
},
);
}
}