Flutter嚐鮮2——動畫處理<基礎>

本例的代碼參考這裏

概述

動畫處理的基本原理是,對組件(widget)的某個或某組屬性設置一組連續變化的值,這些值在一定時間間隔內不斷被應用到該屬性上,使得組件的外觀看上去在進行平滑而連續的變動。

例如2秒內每隔0.1s將一個組件的x軸座標加1,那麼該組件看上去就是從左至右移動了2秒共20個單位。
圖片描述

處理組成部分

具體到Flutter,動畫處理主要分爲三個部分:

  • 動畫控制器(AnimationController),控制整個動畫運行,包括開始結束和動畫時長等。
  • 動畫抽象(Animation),描述了動畫運動的速率,例如組件是加速還是勻速,或者其它變化。
  • 變動範圍(Tween),定義了動畫組件屬性值的變化範圍,例如從座標(0, 0)移動到(20, 0)

處理流程

上述三大組件,控制了整個動畫的運行。用文字描述,其流程主要包括:

  1. 初始化動畫控制器,設定動畫的時長,初始值等(如上例:2秒時長)
  2. 初始化變動範圍(如上例:Offset從[0, 0]到[20, 0])
  3. 初始化動畫抽象,定義它的運動速率(如上例:勻速變動)
  4. 將動畫描述的值,賦值到動畫組件的對應屬性上
  5. 開始執行動畫(調用動畫控制器的開始方法)
  6. 動畫執行結束

AnimationController定義

AnimationController是一個特殊的Animation對象。創建一個AnimationController時,需要傳遞一個vsync參數。設置此參數的目的,是希望屏幕每一幀畫面變化時能夠被通知到。也就是說,屏幕刷新的每一幀,AnimationController都會生成一個新的值(同樣也意味着,如果在屏幕外那麼就不被觸發)。這樣動畫組件就能夠完成一個連續平滑的動畫動作。

Tickers can be used by any object that wants to be notified whenever a frame triggers。

AnimationControler通常是在一個StatefulWidget中被聲明,並且附帶一個叫做SingleTickerProviderStateMixin的Mixin(原因就在上面說的,要設置vsync參數)。

class AnimationDemo extends StatefulWidget {
    AnimationDemoState createState() => AnimationDemoState();
}

class AnimationDemoState extends State<AnimationDemo> with SingleTickerProviderStateMixin {
    
    AnimationController controller;
    
    @override
    void initState() {
        super.initState();
        
        controller = AnimationController(duration: Duration(milliseconds: 2000), vsync: this);
        ...
    }
    
    @override
    void dispose() {
        controller.dispose();  // 離開時需要銷燬controller
        super.dispose();
    }
    ...
}

當Animation和Tween的設置完成後,簡單調用controller.forward()即可開始動畫。

Tween定義

Tween就是要改變的屬性值的變動範圍。它可以是任意的屬性類如Offset或者Color,最常見的是double。

...
    AnimationController controller;
    Tween<double> slideTween = Tween(begin: 0.0, end: 20.0);
...

Animation定義

Animation對象本身可以看做是動畫中所有變化值的一個集合。它包含了變化區間內的所有可取值,並返回給動畫組件當前的變動值。

Animation在使用中要設置的,是他的變動速率,如Curves.linear(線性變化)。

...
    AnimationController controller;
    Tween<double> slideTween = Tween(begin: 0.0, end: 20.0);
    Animation<double> animation;
    
    @override
    void initState() {
        super.initState();
        
        ...
        animation = slideTween.animate(CurvedAnimation(parent: controller, curve: Curves.linear));
    }
...

動畫組件定義

爲了說明簡單,在build方法中嵌套兩個Container組件,外部容器Container的paddingLeft跟隨動畫變動,達到移動內部Container的目的。

class AnimationDemoState extends State<AnimationDemo> with SingleTickerProviderStateMixin {
    ...
    
    @override
    Widget build(BuildContext context) {
        return Container(
            width: 200,
            alignment: Alignment.centerLeft,
            padding: EdgeInsets.only(left: animation.value),
            child: Container(
              color: Colors.blue,
              width: 80,
              height: 80,
            ),
        );
    }
}

啓動動畫

在啓動動畫之前有一個Flutter的基本概念要說明。做過React的同學很清楚,要想render方法重新執行,要麼props有更新要麼state有更新。在Flutter也同樣如此,build方法同樣依賴於state的更新才能重新執行。

在AnimationController的說明中,我們知道因爲設置了vsync所以屏幕刷新的每一幀都會更新它的值。所以可以在Controller上加上一個listener,每次有update都調用一下setState,以此達到重新渲染UI的目的。

...
    @override
    void initState() {
        ...
        animation.addListener(() => this.setState(() {}));

        controller.repeat(); // 動畫重複執行
    }

調用controller.repeat()方法,動畫會被反覆執行。如果想只執行一次,那麼可以使用controller.forward();

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章