Flutter實(shí)戰(zhàn) 交織動(dòng)畫(huà)

2021-03-08 18:01 更新

有些時(shí)候我們可能會(huì)需要一些復(fù)雜的動(dòng)畫(huà),這些動(dòng)畫(huà)可能由一個(gè)動(dòng)畫(huà)序列或重疊的動(dòng)畫(huà)組成,比如:有一個(gè)柱狀圖,需要在高度增長(zhǎng)的同時(shí)改變顏色,等到增長(zhǎng)到最大高度后,我們需要在X軸上平移一段距離。可以發(fā)現(xiàn)上述場(chǎng)景在不同階段包含了多種動(dòng)畫(huà),要實(shí)現(xiàn)這種效果,使用交織動(dòng)畫(huà)(Stagger Animation)會(huì)非常簡(jiǎn)單。交織動(dòng)畫(huà)需要注意以下幾點(diǎn):

  1. 要?jiǎng)?chuàng)建交織動(dòng)畫(huà),需要使用多個(gè)動(dòng)畫(huà)對(duì)象(Animation)。
  2. 一個(gè)AnimationController控制所有的動(dòng)畫(huà)對(duì)象。
  3. 給每一個(gè)動(dòng)畫(huà)對(duì)象指定時(shí)間間隔(Interval)

所有動(dòng)畫(huà)都由同一個(gè) AnimationController (opens new window) 驅(qū)動(dòng),無(wú)論動(dòng)畫(huà)需要持續(xù)多長(zhǎng)時(shí)間,控制器的值必須在0.0到1.0之間,而每個(gè)動(dòng)畫(huà)的間隔(Interval)也必須介于0.0和1.0之間。對(duì)于在間隔中設(shè)置動(dòng)畫(huà)的每個(gè)屬性,需要分別創(chuàng)建一個(gè) Tween (opens new window)用于指定該屬性的開(kāi)始值和結(jié)束值。也就是說(shuō)0.0到1.0代表整個(gè)動(dòng)畫(huà)過(guò)程,我們可以給不同動(dòng)畫(huà)指定不同的起始點(diǎn)和終止點(diǎn)來(lái)決定它們的開(kāi)始時(shí)間和終止時(shí)間。

#示例

下面我們看一個(gè)例子,實(shí)現(xiàn)一個(gè)柱狀圖增長(zhǎng)的動(dòng)畫(huà):

  1. 開(kāi)始時(shí)高度從0增長(zhǎng)到300像素,同時(shí)顏色由綠色漸變?yōu)榧t色;這個(gè)過(guò)程占據(jù)整個(gè)動(dòng)畫(huà)時(shí)間的60%。
  2. 高度增長(zhǎng)到300后,開(kāi)始沿X軸向右平移100像素;這個(gè)過(guò)程占用整個(gè)動(dòng)畫(huà)時(shí)間的40%。

我們將執(zhí)行動(dòng)畫(huà)的 Widget 分離出來(lái):

  1. class StaggerAnimation extends StatelessWidget {
  2. StaggerAnimation({ Key key, this.controller }): super(key: key){
  3. //高度動(dòng)畫(huà)
  4. height = Tween<double>(
  5. begin:.0 ,
  6. end: 300.0,
  7. ).animate(
  8. CurvedAnimation(
  9. parent: controller,
  10. curve: Interval(
  11. 0.0, 0.6, //間隔,前60%的動(dòng)畫(huà)時(shí)間
  12. curve: Curves.ease,
  13. ),
  14. ),
  15. );
  16. color = ColorTween(
  17. begin:Colors.green ,
  18. end:Colors.red,
  19. ).animate(
  20. CurvedAnimation(
  21. parent: controller,
  22. curve: Interval(
  23. 0.0, 0.6,//間隔,前60%的動(dòng)畫(huà)時(shí)間
  24. curve: Curves.ease,
  25. ),
  26. ),
  27. );
  28. padding = Tween<EdgeInsets>(
  29. begin:EdgeInsets.only(left: .0),
  30. end:EdgeInsets.only(left: 100.0),
  31. ).animate(
  32. CurvedAnimation(
  33. parent: controller,
  34. curve: Interval(
  35. 0.6, 1.0, //間隔,后40%的動(dòng)畫(huà)時(shí)間
  36. curve: Curves.ease,
  37. ),
  38. ),
  39. );
  40. }
  41. final Animation<double> controller;
  42. Animation<double> height;
  43. Animation<EdgeInsets> padding;
  44. Animation<Color> color;
  45. Widget _buildAnimation(BuildContext context, Widget child) {
  46. return Container(
  47. alignment: Alignment.bottomCenter,
  48. padding:padding.value ,
  49. child: Container(
  50. color: color.value,
  51. width: 50.0,
  52. height: height.value,
  53. ),
  54. );
  55. }
  56. @override
  57. Widget build(BuildContext context) {
  58. return AnimatedBuilder(
  59. builder: _buildAnimation,
  60. animation: controller,
  61. );
  62. }
  63. }

StaggerAnimation中定義了三個(gè)動(dòng)畫(huà),分別是對(duì)Containerheight、colorpadding屬性設(shè)置的動(dòng)畫(huà),然后通過(guò)Interval來(lái)為每個(gè)動(dòng)畫(huà)指定在整個(gè)動(dòng)畫(huà)過(guò)程中的起始點(diǎn)和終點(diǎn)。下面我們來(lái)實(shí)現(xiàn)啟動(dòng)動(dòng)畫(huà)的路由:

  1. class StaggerRoute extends StatefulWidget {
  2. @override
  3. _StaggerRouteState createState() => _StaggerRouteState();
  4. }
  5. class _StaggerRouteState extends State<StaggerRoute> with TickerProviderStateMixin {
  6. AnimationController _controller;
  7. @override
  8. void initState() {
  9. super.initState();
  10. _controller = AnimationController(
  11. duration: const Duration(milliseconds: 2000),
  12. vsync: this
  13. );
  14. }
  15. Future<Null> _playAnimation() async {
  16. try {
  17. //先正向執(zhí)行動(dòng)畫(huà)
  18. await _controller.forward().orCancel;
  19. //再反向執(zhí)行動(dòng)畫(huà)
  20. await _controller.reverse().orCancel;
  21. } on TickerCanceled {
  22. // the animation got canceled, probably because we were disposed
  23. }
  24. }
  25. @override
  26. Widget build(BuildContext context) {
  27. return GestureDetector(
  28. behavior: HitTestBehavior.opaque,
  29. onTap: () {
  30. _playAnimation();
  31. },
  32. child: Center(
  33. child: Container(
  34. width: 300.0,
  35. height: 300.0,
  36. decoration: BoxDecoration(
  37. color: Colors.black.withOpacity(0.1),
  38. border: Border.all(
  39. color: Colors.black.withOpacity(0.5),
  40. ),
  41. ),
  42. //調(diào)用我們定義的交織動(dòng)畫(huà)Widget
  43. child: StaggerAnimation(
  44. controller: _controller
  45. ),
  46. ),
  47. ),
  48. );
  49. }
  50. }

執(zhí)行效果如圖,點(diǎn)擊圖9-3灰色矩形,就可以看到整個(gè)動(dòng)畫(huà)效果,圖9-4是動(dòng)畫(huà)執(zhí)行過(guò)程中的一幀。

圖9-3圖9-4

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)