第10章:Flutter 动画与交互效果
优秀的 App UI 离不开动画和交互设计。Flutter 拥有强大的动画系统,支持声明式动画、隐式动画、显式动画、过渡动画等,几乎可以满足你对动效的所有想象。
一、Flutter 动画系统简介
类型 | 说明 | 示例组件 |
---|---|---|
隐式动画 | 自动处理状态变化的过渡动画 | AnimatedContainer , AnimatedOpacity |
显式动画 | 完全自定义动画控制器、曲线、时长等 | AnimationController , Tween |
过渡动画 | 页面间跳转动画 | Hero , PageRouteBuilder |
二、隐式动画(最简单易用)
1. AnimatedContainer
class MyAnimatedBox extends StatefulWidget {
@override
_MyAnimatedBoxState createState() => _MyAnimatedBoxState();
}
class _MyAnimatedBoxState extends State<MyAnimatedBox> {
double _width = 100;
void _toggle() {
setState(() {
_width = _width == 100 ? 200 : 100;
});
}
@override
Widget build(BuildContext context) {
return Column(
children: [
AnimatedContainer(
width: _width,
height: 100,
duration: Duration(milliseconds: 300),
color: Colors.blue,
),
ElevatedButton(onPressed: _toggle, child: Text("Animate"))
],
);
}
}
2. AnimatedOpacity(透明动画)
AnimatedOpacity(
opacity: _visible ? 1.0 : 0.0,
duration: Duration(seconds: 1),
child: Text("Hello Flutter"),
)
三、显式动画(高级控制)
1. AnimationController + Tween + AnimatedBuilder
class MyFadeIn extends StatefulWidget {
@override
_MyFadeInState createState() => _MyFadeInState();
}
class _MyFadeInState extends State<MyFadeIn> with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _fade;
@override
void initState() {
super.initState();
_controller = AnimationController(duration: Duration(seconds: 2), vsync: this);
_fade = Tween(begin: 0.0, end: 1.0).animate(_controller);
_controller.forward(); // 启动动画
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _fade,
builder: (_, child) => Opacity(opacity: _fade.value, child: child),
child: Text("Fade In Text", style: TextStyle(fontSize: 24)),
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}
2. TweenAnimationBuilder(简化 Tween 动画)
TweenAnimationBuilder<double>(
tween: Tween(begin: 0, end: 1),
duration: Duration(seconds: 1),
builder: (context, value, child) {
return Opacity(opacity: value, child: child);
},
child: Text("Tween Fade"),
)
四、页面过渡动画(Hero 动画)
用于两个页面之间共享一个元素的“跳转动效”。
示例:
页面 A:
Hero(
tag: 'hero-image',
child: Image.asset('assets/image.png', width: 100),
)
页面 B:
Hero(
tag: 'hero-image',
child: Image.asset('assets/image.png', width: 300),
)
注意:
tag
要一致- 图片或 Widget 类型一致性要高
五、交互动画推荐组件
组件 | 作用 |
---|---|
AnimatedCrossFade | 两个组件之间渐变切换 |
AnimatedSwitcher | 子组件变化时动画切换 |
AnimatedIcon | Flutter 自带动画图标 |
InteractiveViewer | 支持拖拽、缩放、旋转 |
Draggable / DragTarget | 实现拖拽交互(如拖动文件) |
六、常见问题解析
❗ 动画不生效或不流畅?
- 忘记使用
StatefulWidget
- 控制器未调用
forward()
或未释放资源 - 使用动画嵌套组件时嵌套层级过深,建议合理拆分
❗ Hero 动画跳转失败?
- 检查两个页面的
Hero
是否都设置了相同tag
child
类型不一致,例如一个用的是Image.asset
,另一个用了ClipRRect + Image.asset
❗ Tween 数值类型不匹配?
Tween<double>
对应的是double
Tween<Offset>
、Tween<Color>
要用对应类型