本例的代码参考这里。
并行动画
当多个动画定义同时指向某个组件,并使用动画控制器启动时,就产生了并行动画(Parallel Animation)。例如我们可以让一个组件:
移动的同时改变大小
旋转的同时边界颜色闪烁
圆形图片模糊的同时形状越来越方
总之,掌握了动画原理以后我们知道,只要能将一个动画抽象值与一个组件的某个外观属性值联系起来,那么就能在动画中展现出连续平滑的外观变化。这一点,任何平台(Web、Android)的原理都是一致的。
例子
接前一篇的例子,我们让一个移动的正方形在位移过程中逐渐变为圆形。
在已有的 animation 基础上,再添加一个新的 animation 用以控制动画组件的边角半径。
class ParallelDemoState extends State<ParallelDemo> with SingleTickerProviderStateMixin {
…
Tween<double> slideTween = Tween(begin: 0.0, end: 200.0);
Tween<double> borderTween = Tween(begin: 0.0, end: 40.0); // 添加边角半径变动范围
Animation<double> slideAnimation;
Animation<double> borderAnimation; // 添加边角半径动画定义
@override
void initState() {
…
controller = AnimationController(duration: Duration(milliseconds: 2000), vsync: this);
slideAnimation = slideTween.animate(CurvedAnimation(parent: controller, curve: Curves.linear));
borderAnimation = borderTween.animate(CurvedAnimation(parent: controller, curve: Curves.linear)); // 定义边角半径动画
}
…
@override
Widget build(BuildContext context) {
return Container(
width: 200,
alignment: Alignment.centerLeft,
child: Container(
margin: EdgeInsets.only(left: slideAnimation.value),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(borderAnimation.value), // 边角半径的属性上添加动画
color: Colors.blue,
),
width: 80,
height: 80,
),
);
}
}
串行动画
串行动画(Sequential Animation)顾名思义,多个动画像肉串一样一个接一个的发生。但这只是从现象上观察出的结果,实际的运行方式和并行动画差别不大。串行动画的关键之处在于,它为每个动画的发生设定了一个计时器,只有到特定时间点时,特定的动画效果才会发生。
例如设计一个 3 秒钟的动画:
移动动画从 0 秒开始,持续 1 秒
旋转动画从 1 秒开始,持续 1.5 秒
缩放动画从 2 秒开始,持续 0.7 秒
那么,最后的动画效果便是:
0~1 秒,动画元素在移动
1~2 秒,动画元素在旋转
2~2.5 秒,动画既在旋转又在缩放
2.5~2.7 秒,动画在缩放
2.7~3 秒,动画静止不动
例子
在串行动画例子的基础上,我们加上计时器 Interval 的处理。Interval 有三个参数,前两个参数指示了动画的开始和结束时间。这两个参数都是以动画控制器的 Duration 时长的比例来计算的。例如:
Slide 动画分别为 0.0 和 0.5,表示动画从 0 秒(2000ms 0.0)这个时间点开始,至 1 秒(2000ms 0.5) 这个时间点结束
Border 动画分别为 0.5 和 1.0,表示动画从 1 秒(2000ms 0.5)这个时间点开始,至 2 秒(2000ms 1.0)这个时间点结束
class SequentialDemoState extends State<ParallelDemo> with SingleTickerProviderStateMixin {
…
@override
void initState() {
…
controller = AnimationController(duration: Duration(milliseconds: 2000), vsync: this);
// slideAnimation = slideTween.animate(CurvedAnimation(parent: controller, curve: Curves.linear));
// borderAnimation = borderTween.animate(CurvedAnimation(parent: controller, curve: Curves.linear)); // 定义边角半径动画
// 换一种写法,加入 Interval
slideAnimation = slideTween.animate(CurveTween(curve: Interval(0.0, 0.5, curve: Curves.linear)).animate(controller));
borderAnimation = borderTween.animate(CurveTween(curve: Interval(0.5, 1.0, curve: Curves.linear)).animate(controller));
}
…
@override
Widget build(BuildContext context) {
return Container(
width: 200,
alignment: Alignment.centerLeft,
child: Container(
margin: EdgeInsets.only(left: slideAnimation.value),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(borderAnimation.value), // 边角半径的属性上添加动画
color: Colors.blue,
),
width: 80,
height: 80,
),
);
}
}