Flutter中 动画分类
Flutter动画开发指南 本文系统介绍了Flutter动画开发的核心内容,主要包括: 动画分类:隐式动画(如AnimatedContainer)和显式动画(如AnimationController) 核心组件:AnimationController控制器、Tween补间动画和AnimationBuilder构建器 常用隐式动画组件:包括AnimatedOpacity、AnimatedPositi
·
本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新
一、Flutter动画分类
1.1 基于实现方式分类
// 1. 隐式动画(Implicit Animation)
AnimatedContainer(
duration: Duration(seconds: 1),
width: _isExpanded ? 200 : 100,
height: _isExpanded ? 200 : 100,
color: _isSelected ? Colors.blue : Colors.grey,
)
// 2. 显式动画(Explicit Animation)
AnimationController(
duration: Duration(seconds: 2),
vsync: this,
)
1.2 基于动画类型分类
-
补间动画(Tween Animation):在两个值之间过渡
-
物理动画(Physics-based Animation):模拟物理效果
-
交错动画(Staggered Animation):多个动画按顺序执行
-
自定义动画(Custom Animation):使用CustomPainter创建
二、核心动画组件
2.1 AnimationController - 动画控制器
class _MyAnimationState extends State<MyAnimation>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
@override
void initState() {
super.initState();
// 创建AnimationController
_controller = AnimationController(
duration: Duration(seconds: 2), // 动画时长
vsync: this, // 垂直同步,防止屏幕外动画消耗资源
lowerBound: 0.0, // 最小值
upperBound: 1.0, // 最大值
);
// 添加状态监听
_controller.addStatusListener((status) {
if (status == AnimationStatus.completed) {
// 动画完成时的操作
_controller.reverse();
} else if (status == AnimationStatus.dismissed) {
// 动画消失时的操作
_controller.forward();
}
});
}
@override
void dispose() {
_controller.dispose(); // 必须释放资源
super.dispose();
}
}
2.2 Tween - 补间动画
// 创建补间动画
Animation<double> _animation;
Animation<Color?> _colorAnimation;
Animation<BorderRadius?> _borderRadiusAnimation;
@override
void initState() {
super.initState();
// 创建颜色补间动画
_colorAnimation = ColorTween(
begin: Colors.red,
end: Colors.blue,
).animate(_controller);
// 创建圆角补间动画
_borderRadiusAnimation = BorderRadiusTween(
begin: BorderRadius.circular(0),
end: BorderRadius.circular(50),
).animate(_controller);
// 创建多个属性的补间动画
_animation = Tween<double>(begin: 0, end: 300).animate(
CurvedAnimation(
parent: _controller,
curve: Curves.easeInOut, // 动画曲线
),
);
}
2.3 AnimationBuilder - 动画构建器
AnimatedBuilder(
animation: _controller,
builder: (context, child) {
return Transform.rotate(
angle: _controller.value * 2 * pi, // 旋转动画
child: Container(
width: 100,
height: 100,
color: Colors.blue,
),
);
},
)
三、隐式动画组件
3.1 常用隐式动画组件
// 1. AnimatedContainer - 容器动画
AnimatedContainer(
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
width: _isExpanded ? 200 : 100,
height: _isExpanded ? 200 : 100,
color: _color,
alignment: _alignment,
padding: _padding,
margin: _margin,
transform: _transform,
child: Text('Animated Container'),
)
// 2. AnimatedOpacity - 透明度动画
AnimatedOpacity(
duration: Duration(seconds: 1),
opacity: _visible ? 1.0 : 0.0,
child: Container(
width: 200,
height: 200,
color: Colors.blue,
),
)
// 3. AnimatedPositioned - 位置动画(在Stack中使用)
Stack(
children: [
AnimatedPositioned(
duration: Duration(seconds: 1),
left: _isRight ? 100 : 0,
top: _isBottom ? 100 : 0,
child: Container(
width: 100,
height: 100,
color: Colors.red,
),
),
],
)
// 4. AnimatedAlign - 对齐动画
AnimatedAlign(
duration: Duration(seconds: 1),
alignment: _alignment,
child: Container(
width: 100,
height: 100,
color: Colors.green,
),
)
// 5. AnimatedPadding - 内边距动画
AnimatedPadding(
duration: Duration(seconds: 1),
padding: _hasPadding ? EdgeInsets.all(20) : EdgeInsets.zero,
child: Container(
color: Colors.orange,
child: Text('Padding Animation'),
),
)
// 6. AnimatedDefaultTextStyle - 文本样式动画
AnimatedDefaultTextStyle(
duration: Duration(seconds: 1),
style: _isBigText
? TextStyle(fontSize: 30, color: Colors.red)
: TextStyle(fontSize: 14, color: Colors.black),
child: Text('Text Style Animation'),
)
// 7. AnimatedCrossFade - 交叉淡入淡出
AnimatedCrossFade(
duration: Duration(seconds: 1),
firstChild: Container(
width: 200,
height: 200,
color: Colors.blue,
child: Center(child: Text('First')),
),
secondChild: Container(
width: 200,
height: 100,
color: Colors.green,
child: Center(child: Text('Second')),
),
crossFadeState: _showFirst
? CrossFadeState.showFirst
: CrossFadeState.showSecond,
)
// 8. AnimatedSwitcher - 切换动画
AnimatedSwitcher(
duration: Duration(seconds: 1),
transitionBuilder: (child, animation) {
return ScaleTransition(
scale: animation,
child: child,
);
},
child: _currentWidget,
)
四、显式动画流程
class ExplicitAnimationExample extends StatefulWidget {
@override
_ExplicitAnimationExampleState createState() => _ExplicitAnimationExampleState();
}
class _ExplicitAnimationExampleState extends State<ExplicitAnimationExample>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _animation;
late Animation<Color?> _colorAnimation;
@override
void initState() {
super.initState();
// 1. 创建控制器
_controller = AnimationController(
duration: Duration(seconds: 2),
vsync: this,
);
// 2. 创建动画曲线
final CurvedAnimation curvedAnimation = CurvedAnimation(
parent: _controller,
curve: Curves.easeInOut,
);
// 3. 创建补间动画
_animation = Tween<double>(
begin: 0,
end: 300,
).animate(curvedAnimation);
// 4. 创建颜色动画
_colorAnimation = ColorTween(
begin: Colors.red,
end: Colors.blue,
).animate(curvedAnimation);
// 5. 添加状态监听
_controller.addStatusListener((status) {
if (status == AnimationStatus.completed) {
_controller.reverse();
} else if (status == AnimationStatus.dismissed) {
_controller.forward();
}
});
// 6. 启动动画
_controller.forward();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _controller,
builder: (context, child) {
return Center(
child: Container(
width: _animation.value,
height: _animation.value,
color: _colorAnimation.value,
child: Center(
child: Text(
'${(_controller.value * 100).round()}%',
style: TextStyle(color: Colors.white),
),
),
),
);
},
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}
五、自定义动画
5.1 使用CustomPainter创建自定义动画
class ParticleSystemPainter extends CustomPainter {
final List<Particle> particles;
final double time;
ParticleSystemPainter(this.particles, this.time);
@override
void paint(Canvas canvas, Size size) {
for (var particle in particles) {
// 计算粒子位置
final x = particle.x + particle.vx * time;
final y = particle.y + particle.vy * time - 0.5 * 9.8 * time * time;
// 绘制粒子
final paint = Paint()
..color = particle.color.withOpacity(1 - time / 2)
..style = PaintingStyle.fill;
canvas.drawCircle(
Offset(x, y),
particle.radius * (1 - time / 3),
paint,
);
}
}
@override
bool shouldRepaint(covariant ParticleSystemPainter oldDelegate) {
return particles != oldDelegate.particles || time != oldDelegate.time;
}
}
class Particle {
final double x, y;
final double vx, vy;
final double radius;
final Color color;
Particle(this.x, this.y, this.vx, this.vy, this.radius, this.color);
}
class ParticleAnimation extends StatefulWidget {
@override
_ParticleAnimationState createState() => _ParticleAnimationState();
}
class _ParticleAnimationState extends State<ParticleAnimation>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late List<Particle> particles;
@override
void initState() {
super.initState();
particles = List.generate(50, (index) {
return Particle(
Random().nextDouble() * 300,
Random().nextDouble() * 300,
Random().nextDouble() * 10 - 5,
Random().nextDouble() * 20 - 10,
Random().nextDouble() * 5 + 2,
Colors.primaries[Random().nextInt(Colors.primaries.length)],
);
});
_controller = AnimationController(
duration: Duration(seconds: 3),
vsync: this,
)..repeat();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _controller,
builder: (context, child) {
return CustomPaint(
painter: ParticleSystemPainter(particles, _controller.value),
size: Size(300, 300),
);
},
);
}
}
六、代码是例
旋转加载动画
class LoadingSpinner extends StatefulWidget {
final Color color;
final double size;
const LoadingSpinner({
Key? key,
this.color = Colors.blue,
this.size = 50,
}) : super(key: key);
@override
_LoadingSpinnerState createState() => _LoadingSpinnerState();
}
class _LoadingSpinnerState extends State<LoadingSpinner>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: Duration(seconds: 1),
vsync: this,
)..repeat();
}
@override
Widget build(BuildContext context) {
return RotationTransition(
turns: _controller,
child: Container(
width: widget.size,
height: widget.size,
decoration: BoxDecoration(
color: widget.color,
shape: BoxShape.circle,
),
child: CustomPaint(
painter: _SpinnerPainter(widget.color),
),
),
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}
class _SpinnerPainter extends CustomPainter {
final Color color;
_SpinnerPainter(this.color);
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..color = color.withOpacity(0.3)
..strokeWidth = 4
..style = PaintingStyle.stroke;
canvas.drawCircle(
Offset(size.width / 2, size.height / 2),
size.width / 2 - 2,
paint,
);
final gradientPaint = Paint()
..shader = SweepGradient(
colors: [Colors.transparent, color],
stops: [0.0, 0.75],
startAngle: 0,
endAngle: pi * 1.5,
).createShader(Rect.fromCircle(
center: Offset(size.width / 2, size.height / 2),
radius: size.width / 2 - 2,
))
..strokeWidth = 4
..style = PaintingStyle.stroke
..strokeCap = StrokeCap.round;
canvas.drawArc(
Rect.fromCircle(
center: Offset(size.width / 2, size.height / 2),
radius: size.width / 2 - 2,
),
0,
pi * 1.5,
false,
gradientPaint,
);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}
更多推荐
所有评论(0)