本例的代碼參考這裏。
並行動畫
當多個動畫定義同時指向某個組件,並使用動畫控制器啓動時,就產生了並行動畫(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,
),
);
}
}