多个动画组合在一起,可能有重叠。每个动画对应一个 Tween 对象,一个 AnimationController 控制所有动画。AnimationController 的值必须在 0.0 到 1.0 之间。
先看一个简单的例子:
class AnimatedLogo extends AnimatedWidget {
// 两个 Animation
static final _opacityTween = new Tween<double>(begin: 0.1, end: 1.0);
static final _sizeTween = new Tween<double>(begin: 0.0, end: 300.0);
AnimatedLogo({Key key, Animation<double> animation})
: super(key: key, listenable: animation);
Widget build(BuildContext context) {
final Animation<double> animation = listenable;
return Center(
child: new Opacity(
// 透明度动画
opacity: _opacityTween.evaluate(animation),
child: new Container(
margin: new EdgeInsets.symmetric(vertical: 10.0),
// 尺寸动画
height: _sizeTween.evaluate(animation),
width: _sizeTween.evaluate(animation),
child: new FlutterLogo(),
),
),
);
}
}
//...
class AnimState extends State<AnimScreen> with SingleTickerProviderStateMixin {
Animation<double> animation;
AnimationController controller;
@override
initState() {
super.initState();
controller = new AnimationController(
duration: const Duration(milliseconds: 2000), vsync: this);
animation = new CurvedAnimation(parent: controller, curve: Curves.easeIn);
controller.forward();
}
Widget build(BuildContext context) {
return AnimatedLogo(animation: animation);
}
// ...
}
对于原来 Animation
animation = Tween(begin: 0.0, end: 300.0).animate(controller)
看 animate 方法的定义
Animation<T> animate(Animation<double> parent) {
return _AnimatedEvaluation<T>(parent, this);
}
而以后调用 .value
时,看源码
@override
T get value => _evaluatable.evaluate(parent);
所以 _sizeTween.evaluate(animation)
这种用法和原来是等价的,只是原来先通过 animation()
方法返回了 Animation,然后直接调用这个 Animation 的 value。现在是直接在 Tween 上通过 evaluate 方法把外界的 Animation 传进去。
下面是个更复杂的例子,在 0.0 到 1.0 间连续做六个动画
15481272243303.png六个动画创建六个 Tween,创建一个类管理这六个动画,在构造时创建对象
class StaggerAnimation extends StatelessWidget {
final Animation<double> controller;
final Animation<double> opacity;
final Animation<double> width;
final Animation<double> height;
final Animation<EdgeInsets> padding;
final Animation<BorderRadius> borderRadius;
final Animation<Color> color;
StaggerAnimation({ Key key, this.controller }) :
opacity = Tween<double>(
begin: 0.0,
end: 1.0,
).animate(
CurvedAnimation(
parent: controller,
curve: Interval(
0.0, 0.100,
curve: Curves.ease,
),
),
),
width = Tween<double>(
begin: 50.0,
end: 150.0,
).animate(
CurvedAnimation(
parent: controller,
curve: Interval(
0.125, 0.250,
curve: Curves.ease,
),
),
),
height = Tween<double>(
begin: 50.0,
end: 150.0
).animate(
CurvedAnimation(
parent: controller,
curve: Interval(
0.250, 0.375,
curve: Curves.ease,
),
),
),
padding = EdgeInsetsTween(
begin: const EdgeInsets.only(bottom: 16.0),
end: const EdgeInsets.only(bottom: 75.0),
).animate(
CurvedAnimation(
parent: controller,
curve: Interval(
0.250, 0.375,
curve: Curves.ease,
),
),
),
borderRadius = BorderRadiusTween(
begin: BorderRadius.circular(4.0),
end: BorderRadius.circular(75.0),
).animate(
CurvedAnimation(
parent: controller,
curve: Interval(
0.375, 0.500,
curve: Curves.ease,
),
),
),
color = ColorTween(
begin: Colors.indigo[100],
end: Colors.orange[400],
).animate(
CurvedAnimation(
parent: controller,
curve: Interval(
0.500, 0.750,
curve: Curves.ease,
),
),
),
super(key: key);
}
然后重写 build 方法
final Animation<double> controller;
Widget _buildAnimation(BuildContext context, Widget child) {
return Container(
padding: padding.value, // 内边距动画
alignment: Alignment.bottomCenter,
child: Opacity(
opacity: opacity.value, // 透明度动画
child: Container(
width: width.value, // 宽度动画
height: height.value, // 高度动画
decoration: BoxDecoration(
color: color.value, // 颜色动画
border: Border.all(
color: Colors.indigo[300],
width: 3.0,
),
borderRadius: borderRadius.value, // 圆角动画
),
),
),
);
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
builder: _buildAnimation, // 动画变化时调用这个函数
animation: controller, // 要执行的动画
);
}
然后构建要做动画的 Widget
class StaggerDemo extends StatefulWidget {
@override
_StaggerDemoState createState() => _StaggerDemoState();
}
class _StaggerDemoState extends State<StaggerDemo> with TickerProviderStateMixin {
AnimationController _controller;
@override
void initState() {
super.initState();
// 构建一个 Controller
_controller = AnimationController(
duration: const Duration(milliseconds: 2000),
vsync: this
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
Future<void> _playAnimation() async {
try {
// 执行一遍再逆向执行一遍
await _controller.forward().orCancel;
await _controller.reverse().orCancel;
} on TickerCanceled {
}
}
@override
Widget build(BuildContext context) {
timeDilation = 10.0;
return Scaffold(
appBar: AppBar(
title: const Text('Staggered Animation'),
),
body: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
_playAnimation();
},
child: Center(
child: Container(
width: 300.0,
height: 300.0,
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.1),
border: Border.all(
color: Colors.black.withOpacity(0.5),
),
),
child: StaggerAnimation(
controller: _controller.view
),
),
),
),
);
}
}
AnimationController 是 2000ms,而最后的 0.25 没有执行某个动画,逆序最开始也有 0.25,所以中间会有 2000*0.5=1000ms 的时间没有动画效果(Gif 图有点太快了)。
2019-01-22 15_48_53.gif
网友评论