Flutter 动画
AnimatedContainer
通过setState
改变属性值实现动画,transform
属性可影响其子组件。
系统提供了一系列的动画组件:
AnimatedPadding
AnimatedAlign
AnimatedPositioned
AnimatedOpacity
AnimatedDefaultTextStyle
…
double _size = 200;
double _scale = 1.0;
@override
Widget build(BuildContext context) {
return Center(
child: GestureDetector(
onTap: () {
setState(() {
_size = 400;
_scale = 0.5;
});
},
child: AnimatedContainer(
duration: Duration(milliseconds: 500),
curve: Curves.fastOutSlowIn,
width: _size,//子组件的大小不会随之改变
height: _size,
transform: Matrix4.diagonal3Values(_scale, _scale, 1.0),//子组件会随之改变
transformAlignment: Alignment.center,
),
),
);
}
AnimationController + Animation
动画状态:
forward
执行结束状态为 Completed
reverse
执行结束状态为 Dismissed
如果同时有多个AnimationController,且其时长不同,则使用TickerProviderStateMixin
,单个动画控制器使用SingleTickerProviderStateMixin
。
class DemoState extends State<Demo> with SingleTickerProviderStateMixin {
AnimationController _controller;
Animation _scaleAnimation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: Duration(milliseconds: 2000),
vsync: this,
);
_scaleAnimation = Tween(begin: 1.0, end: 0.5).animate(_controller);
_controller.forward();
}
@override
Widget build(BuildContext context) {
return ScaleTransition(
scale: _scaleAnimation,
child: Container(
color: CupertinoColors.activeBlue,
width: 100,
height: 100,
),
);
}
}
例子中使用了ScaleTransition
去实现动画,也有直接使用animation.value
去改变属性值的用法,需要监听controller
变化,然后setState
。
class DemoState extends State<Demo> with SingleTickerProviderStateMixin {
AnimationController _controller;
Animation _animation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: Duration(milliseconds: 2000),
vsync: this,
);
_animation = Tween(begin: 1.0, end: 0.5).animate(_controller);
_controller.addListener(() {
setState(){}
});
_controller.forward();
}
@override
Widget build(BuildContext context) {
return Container(
color: CupertinoColors.activeBlue,
width: 100 * _animation.value,
height: 100 * _animation.value,
);
}
}
不推荐这种用法,简单动画直接使用系统提供的一系列Transition就可以了:
ScaleTransition
SlideTransition
RotationTransition
FadeTransition
SizeTransition
PositionedTransition
RelativePositionedTransition
DecoratedBoxTransition
AlignTransition
DefaultTextStyleTransition
···
若系统提供的Transition无法满足需求,可以使用AnimatedBuilder
系统还有个Transform
类,可以实现旋转平移缩放等操作,但只是变换,没有动画效果。
Transform.rotate()
Transform.translate()
Transform.scale()
RotatedBox()
FittedBox()
…
这些组件都只有变换效果,没有动画。
## AnimatedBuilder + AnimationController 推荐这种用法
final _size = Tween(begin: 100.0, end: 200.0);
final _rotate = Tween(begin: 0.0, end: pi);
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: CurvedAnimation(
parent: _controller,
curve: Curves.linear,
),
builder: (BuildContext context, Widget child) => Container(
width: _size.evaluate(_controller),
height: _size.evaluate(_controller),
transformAlignment: Alignment.center,
transform: Matrix4.rotationZ(_rotate.evaluate(_controller)),
),
);
}
_size.evaluate(_controller)
这个就是Tween
动画随AnimationController
时长变化以及curve
属性而自动计算的值。
TweenAnimationBuilder
TweenAnimationBuilder
已将值变化计算好交给子Widget使用。
使用简单,没有AnimationController
,也无法控制动画的执行时机和重复次数
TweenAnimationBuilder(
duration: Duration(milliseconds: 500),
tween: Tween(begin: 100.0, end: 200.0),
builder: (context, value, child) {
//value的值,实际计算方法就是上面AnimatedBuilder用法中_size.evaluate(_controller)
return Container(
color: CupertinoColors.activeBlue,
width: value,
height: value,
);
},
);