动画组件详解
动画是提升用户体验的关键。Flutter 提供了强大的动画系统,可以轻松创建流畅的动画效果。本教程将详细介绍动画组件和最佳实践。
1. AnimatedContainer 隐式动画
AnimatedContainer 是最简单的动画组件,自动处理属性变化。
📐 AnimatedContainer 动画效果
状态A
状态B
属性变化时自动产生过渡动画 (duration: 300ms)
class AnimatedContainerExample extends StatefulWidget {
const AnimatedContainerExample({super.key});
@override
State createState() =>
_AnimatedContainerExampleState();
}
class _AnimatedContainerExampleState extends State {
double _width = 100;
double _height = 100;
Color _color = Colors.blue;
BorderRadiusGeometry _borderRadius = BorderRadius.circular(8);
void _changeProperties() {
setState(() {
_width = _width == 100 ? 200 : 100;
_height = _height == 100 ? 200 : 100;
_color = _color == Colors.blue ? Colors.red : Colors.blue;
_borderRadius = _borderRadius == BorderRadius.circular(8)
? BorderRadius.circular(50)
: BorderRadius.circular(8);
});
}
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
AnimatedContainer(
width: _width,
height: _height,
decoration: BoxDecoration(
color: _color,
borderRadius: _borderRadius,
),
duration: const Duration(seconds: 1),
curve: Curves.fastOutSlowIn,
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: _changeProperties,
child: const Text('改变属性'),
),
],
),
);
}
}
2. AnimationController 显式动画
使用 AnimationController 创建更复杂的动画。
📐 AnimationController 动画生命周期
forward()
reverse()
repeat()
stop()
value 从 0.0 到 1.0,支持 forward/reverse/repeat/stop 操作
class AnimationControllerExample extends StatefulWidget {
const AnimationControllerExample({super.key});
@override
State createState() =>
_AnimationControllerExampleState();
}
class _AnimationControllerExampleState
extends State
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation _animation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
);
_animation = Tween(
begin: 0,
end: 300,
).animate(CurvedAnimation(
parent: _controller,
curve: Curves.easeInOut,
));
_controller.forward();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Center(
child: AnimatedBuilder(
animation: _animation,
builder: (context, child) {
return Container(
width: _animation.value,
height: _animation.value,
color: Colors.blue,
);
},
),
);
}
}
3. Tween 动画插值
Tween 用于定义动画的起始值和结束值。
📐 Tween 插值类型
ColorTween (颜色)
SizeTween (大小)
Tween<Offset> (位置)
Tween<double> (数值)
Tween 定义动画的 begin 和 end 值,自动计算中间值
// 颜色动画
Animation colorAnimation = ColorTween(
begin: Colors.blue,
end: Colors.red,
).animate(_controller);
// 大小动画
Animation sizeAnimation = SizeTween(
begin: const Size(100, 100),
end: const Size(200, 200),
).animate(_controller);
// 位置动画
Animation offsetAnimation = Tween(
begin: Offset.zero,
end: const Offset(100, 100),
).animate(_controller);
// 使用颜色动画
AnimatedBuilder(
animation: colorAnimation,
builder: (context, child) {
return Container(
width: 100,
height: 100,
color: colorAnimation.value,
);
},
)
4. FadeTransition 淡入淡出
实现透明度变化的动画。
📐 FadeTransition 透明度变化
opacity: 0.0
opacity: 0.3
opacity: 0.6
opacity: 1.0
opacity 从 0.0 到 1.0,实现淡入淡出效果
class FadeTransitionExample extends StatefulWidget {
const FadeTransitionExample({super.key});
@override
State createState() =>
_FadeTransitionExampleState();
}
class _FadeTransitionExampleState extends State
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation _animation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
);
_animation = CurvedAnimation(
parent: _controller,
curve: Curves.easeIn,
);
_controller.repeat(reverse: true);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Center(
child: FadeTransition(
opacity: _animation,
child: const FlutterLogo(
size: 100,
),
),
);
}
}
5. SlideTransition 滑动动画
实现位置滑动的动画。
📐 SlideTransition 位置滑动
Offset(-1, 0)
Offset(-0.5, 0)
Offset(0, 0)
从屏幕外滑入,Offset 范围从 (-1, 0) 到 (0, 0)
class SlideTransitionExample extends StatefulWidget {
const SlideTransitionExample({super.key});
@override
State createState() =>
_SlideTransitionExampleState();
}
class _SlideTransitionExampleState extends State
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation _animation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 1),
vsync: this,
);
_animation = Tween(
begin: const Offset(-1, 0),
end: Offset.zero,
).animate(CurvedAnimation(
parent: _controller,
curve: Curves.easeInOut,
));
_controller.forward();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return SlideTransition(
position: _animation,
child: const Center(
child: FlutterLogo(size: 100),
),
);
}
}
6. ScaleTransition 缩放动画
实现大小缩放的动画。
📐 ScaleTransition 大小缩放
scale: 0.5
scale: 0.8
scale: 1.0
scale: 1.2
scale 从 0 到 1+,实现从小到大的缩放效果
class ScaleTransitionExample extends StatefulWidget {
const ScaleTransitionExample({super.key});
@override
State createState() =>
_ScaleTransitionExampleState();
}
class _ScaleTransitionExampleState extends State
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation _animation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 1),
vsync: this,
);
_animation = CurvedAnimation(
parent: _controller,
curve: Curves.elasticOut,
);
_controller.forward();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Center(
child: ScaleTransition(
scale: _animation,
child: const FlutterLogo(size: 100),
),
);
}
}
7. RotationTransition 旋转动画
实现旋转的动画。
📐 RotationTransition 旋转效果
turns: 0.0
turns: 0.25
turns: 0.5
turns: 0.75
turns: 1.0
turns 从 0.0 到 1.0 表示旋转 0° 到 360°
class RotationTransitionExample extends StatefulWidget {
const RotationTransitionExample({super.key});
@override
State createState() =>
_RotationTransitionExampleState();
}
class _RotationTransitionExampleState extends State
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation _animation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
);
_animation = CurvedAnimation(
parent: _controller,
curve: Curves.linear,
);
_controller.repeat();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Center(
child: RotationTransition(
turns: _animation,
child: const FlutterLogo(size: 100),
),
);
}
}
8. StaggeredAnimation 交错动画
实现多个动画按顺序执行。
📐 StaggeredAnimation 动画序列
步骤 1: 淡入
步骤 2: 缩放
步骤 3: 滑动
使用 Interval 控制每个动画的执行时间,实现序列效果
class StaggeredAnimationExample extends StatefulWidget {
const StaggeredAnimationExample({super.key});
@override
State createState() =>
_StaggeredAnimationExampleState();
}
class _StaggeredAnimationExampleState extends State
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation _fadeAnimation;
late Animation _scaleAnimation;
late Animation _slideAnimation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 3),
vsync: this,
);
_fadeAnimation = Tween(begin: 0, end: 1).animate(
CurvedAnimation(parent: _controller, curve: const Interval(0, 0.3)),
);
_scaleAnimation = Tween(begin: 0.5, end: 1).animate(
CurvedAnimation(parent: _controller, curve: const Interval(0.3, 0.6)),
);
_slideAnimation = Tween(begin: 100, end: 0).animate(
CurvedAnimation(parent: _controller, curve: const Interval(0.6, 1)),
);
_controller.forward();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _controller,
builder: (context, child) {
return Opacity(
opacity: _fadeAnimation.value,
child: Transform.translate(
offset: Offset(0, _slideAnimation.value),
child: Transform.scale(
scale: _scaleAnimation.value,
child: const FlutterLogo(size: 100),
),
),
);
},
);
}
}
🔀 动画实现流程图
📊 动画类型对比
| 类型 | 控制 | 复杂度 | 使用场景 |
|---|---|---|---|
| Animated* | 隐式 | 简单 | 属性动画 |
| AnimationController | 显式 | 复杂 | 自定义动画 |
| Hero | 隐式 | 中等 | 页面过渡 |
| Transition* | 显式 | 中等 | 过渡动画 |
| Staggered | 显式 | 复杂 | 序列动画 |
动画最佳实践
- 优先使用隐式动画(Animated*)简单场景
- 使用显式动画(AnimationController)处理复杂动画
- 始终记得在 dispose 中释放 AnimationController
- 使用合适的曲线让动画更自然
- 避免在 build 方法中创建 AnimationController
- 使用 AnimatedBuilder 减少重建范围
- 合理设置动画时长,避免过长或过短
- 使用 Hero 动画实现页面间共享元素过渡