Flutter動畫詳解

隨著技術的發展,很多網頁開發技術都帶有動畫效果,比如淡入淡出、漸變、變大變小,等等。Flutter中的動畫效果可以用酷炫來形容,這也是Flutter的一大特色。現代的應用程式不僅僅需要程式穩定、好用,還需要好看,體驗好。那麼動畫效果是必不可少的。

/ 動畫概念 /

動畫顧名思義,就是動起來的畫面。如果一直持續的動再加上音訊那就是我們平時看的電影了。那麼畫面為什麼會動起來了呢?在回答這個問題之前,我們先引入一個概念。

人眼在觀察景物時,光訊號傳入大腦神經,需經過一段短暫的時間,光的作用結束後,視覺形象並不立即消失,這種殘留的視覺稱“後像”,視覺的這一現象則被稱為“視覺暫留”。

視覺暫留被認為是電影的最重要的一個理論基礎。我們看到的動畫,實際上是一連串的畫面組成,只不過是以很快的速度去播放,人眼在下一個畫面出來之前,還殘留著上一個畫面的視覺,看起來就像是在沒有間隔的播放這一系列的圖片,也就是我們稱之為的動畫。

幀與FPS

幀就是影像動畫中最小單位的單幅影像畫面,一幀就是一副靜止的畫面。比如我們看到的電影膠片中的每一格即為一幀,電影通常為24幀。

幀又分為關鍵幀和過渡幀,如下所示:

關鍵幀:相當於二維動畫中的原畫,指角色或者物體運動或變化中的關鍵動作所處的那一幀。

過渡幀:關鍵幀與關鍵幀之間的動畫可以由軟體來建立,叫做過渡幀或者中間幀。

FPS(Frame Per Second),即每秒顯示幀的數量。電影每秒播放24幀,即幀率為24FPS。幀率越大則顯示的畫面越流暢,動畫及影片是同一個原理。

插值器/估值器

為了使得動畫呈現出豐富的動畫效果,就需要使用非線性動畫,插值器與估值器可以解決這個問題。概念如下所示:

插值器:設定屬性值從初始值過渡到結束值的變化規律,如勻速、加速及減速等等。即確定了動畫效果變化的模式,如勻速變化、加速變化等等。主要應用於實現非線性運動的動畫效果。

估值器:設定屬性值從初始值過渡到結束值的變化具體數值。估值器的作用是協助插值器實現非線性運動的動畫效果。

插值器決定值的變化規律(勻速、加速),即決定的是變化趨勢,而接下來的具體變化數值則交給估值器。

如:動畫進行了50%(初始值=100,結束值=200 ),那麼勻速插值器計算出了當前屬性值改變的百分比是50%,那麼估值器則負責計算當前屬性值 = 100 + (200-100)x50% = 150。

插值器其實並不複雜,就是一個數學函式,設定屬性值從初始值過渡到結束值的變化規律。每個平臺都有自己定義好的一系列插值器,可以供開發者選擇使用,也提供自定義的介面,本質上是一個貝塞爾函式。

Flutter中的動畫型別

Flutter中動畫分為兩類,如下所示:

補間(Tween)動畫:定義開始點、結束點、時間和速度等引數,然後由框架自動計算如何從開始點過度達到結束點。

基於物理的動畫:模擬真實世界的行為。例如,當你擲球時,球在何處落地,取決於拋球速度有多快、球有多重、距離地面有多遠。

/ Flutter的動畫相關類 /

首先來看下Flutter的動畫基礎概念和相關類,如下所示:

Animation:Flutter中動畫的核心類

AnimationController:動畫管理類

CurvedAnimation:用於定義非線性曲線動畫

Tween:補間物件,用於計算動畫使用的資料範圍之間的插值。

Listeners和StatusListeners:用於監聽動畫狀態改變

Animation介紹

Flutter中的動畫核心類,我們可以理解為Animation是Flutter中動畫的基類。它是個抽象類(abstract),所以不能夠直接建立其物件來使用動畫。Animation具有以下特性:

Animation物件知道動畫的當前狀態(例如,它是開始、停止還是向前或向後移動),但它不知道螢幕上顯示的內容。

Flutter中的Animation物件是一個在一段時間內依次生成一個區間之間值的類。Animation物件的輸出可以是線性的、曲線的、一個步進函式或者任何其他可以設計的對映。根據Animation物件的控制方式,動畫可以反向執行,甚至可以在中間切換方向。

Animation還可以生成除double之外的其他型別值,如:Animation 或 Animation

Animation物件有狀態,可以透過訪問其value屬性獲取動畫的當前值。

Animation物件本身和UI渲染沒有任何關係。

AnimationController動畫管理類

AnimationController是一個特殊的Animation物件。其繼承自Animation ,因此可以在需要Animation物件的任何地方使用它。預設情況下,AnimationController在給定的持續時間內線性生成從0。0到1。0的值。AnimationController在不使用的時候需要dispose,否則會造成資源的洩漏。AnimationController物件建立如下所示:

AnimationController controller = AnimationController(      duration: const Duration(milliseconds: 2000),      vsync: this);

上述是AnimationController 物件的建立方式,建構函式第一個引數是動畫執行的時間,單位是毫秒。第二個vsync傳入是防止動畫離屏之後繼續消耗資源。

vsync物件會繫結動畫的定時器到一個可視的Widget,所以當Widget不顯示時,動畫定時器將會暫停,當Widget再次顯示時,動畫定時器重新恢復執行,這樣就可以避免動畫相關UI不在當前螢幕時消耗資源。如果要使用自定義的State物件作為vsync時,請包含TickerProviderStateMixin,程式碼結構大致如下所示:

class MyApp extends StatefulWidget {  _AnimationApp createState() => _AnimationApp();}class _AnimationApp extends State with SingleTickerProviderStateMixin {    //動畫實現}

這裡需要提一下TickerProvider類,它的主要作用是獲取每一幀重新整理的通知,作用相當於給動畫添加了一個動起來的引擎。

AnimationController 提供了幾個常用的方法。

<!——開始動畫,從開始值向結束值——>TickerFuture forward({ double from }) {}<!——開始反向執行此動畫——>TickerFuture reverse({ double from }) {}<!——開始執行動畫,結束後重新啟動——>TickerFuture repeat({ double min, double max, Duration period }) {}<!——使用阻尼效果驅動動畫——>TickerFuture fling({ double velocity: 1。0 }) {}<!——停止動畫——>void stop({ bool canceled: true }) {}<!——釋放此物件使用的資源,此方法呼叫後不再控制器物件不再可用——>void dispose() {}

CurvedAnimation非線性動畫

CurvedAnimation繼承Animation,它將動畫過程定義為一個非線性曲線,屬於Animation型別。構建其物件的方式如下所示:

CurvedAnimation curve = CurvedAnimation(parent: controller, curve: Curves。easeIn);

建構函式中傳入控制器和要執行的曲線方式。Curves類定義了許多常用的曲線,也可以建立自己的,例如我們使用數學函式Math。sin方法構建一個抖動的曲線,程式碼如下所示:

class ShakeCurve extends Curve {  @override  double transform(double t) {    return math。sin(t * math。PI * 2);  }}

Flutter定義了一系列的插值器,封裝在Curves類中,有下面13種效果:

linear

decelerate

ease

easeIn

easeOut

easeInOut

fastOutSlowIn

bounceIn

bounceOut

bounceInOut

elasticIn

elasticOut

elasticInOut

Tween補間值生成類

AnimationController物件的範圍為0。0到1。0。如果需要不同的範圍或不同的資料型別,可以使用Tween將動畫配置為插入到不同的範圍或資料型別。例如,以下Tween從0。0變為500。0:

Tween doubleTween = Tween(begin: 0。0, end: 500。0);

建構函式傳入只需要傳入begin和end兩個值,當然這裡不一定只是double值。

Tween繼承自Animatable,而不是繼承自Animation。Animatable與Animation相似,不是必須輸出double值。例如,ColorTween指定兩種顏色之間的過渡。

final Tween colorTween = ColorTween(begin: Colors。transparent, end: Colors。black54);

要使用Tween物件,請呼叫其animate()方法,傳入一個控制器物件。例如,以下程式碼在100毫秒內生成從0到200的整數值。

final AnimationController controller = AnimationController(    duration: const Duration(milliseconds: 100), vsync: this);Animation alpha = IntTween(begin: 0, end: 200)。animate(controller);

注意animate()返回的是一個Animation,而不是一個Animatable。

Flutter透過抽象類Animatable來實現估值器。Animatable可以根據不同的輸入,產出不同的數值。透過過載下面的函式來產生不同的估值器。

T transform(double t);

它的最主要的子類是Tween,一個線性的估值器,實現如下,非常的簡單,就是一個線性函式。

T lerp(double t) {  assert(begin != null);  assert(end != null);  //返回值 = 開始值 + (結束值 - 開始值) * 傳入值  return begin + (end - begin) * t;}@overrideT transform(double t) {  //開始  if (t == 0。0)    return begin;  //結束  if (t == 1。0)    return end;  //中間值    return lerp(t);}

在Tween的基礎上實現了不同型別的估值器,如下所示:

ReverseTween

ColorTween

SizeTween

RectTween

IntTween

StepTween

ConstantTween

Listeners和StatusListeners動畫監聽

Animation物件可以有Listeners和StatusListeners,用addListener來進行動畫監聽和addStatusListener進行動畫狀態新增監聽。只要動畫的值發生變化,就會呼叫監聽器。我們通常可用呼叫setState以將動畫重置狀態。動畫開始,結束,前進或後退時呼叫StatusListener,下列是Flutter提供動畫的監聽方法。

<!——動畫新增監聽——>void addListener(VoidCallback listener);<!——動畫移除監聽——>void removeListener(VoidCallback listener);<!——動畫狀態新增監聽——>void addStatusListener(AnimationStatusListener listener);<!——動畫狀態移除監聽——>  void removeStatusListener(AnimationStatusListener listener);

動畫狀態如下:

<!——動畫狀態——>enum AnimationStatus {  <!——動畫在開始時停止——>     dismissed,  <!——動畫從開始狀態執行到結束狀態——>  forward, <!——動畫反向執行,從結束狀態執行到開始狀態——>  reverse, <!——動畫執行完成——>  completed,}

動畫控制流程

當我們理解了插值器(Curve)、估值器(Tween)以及Ticker回撥的原理。我們就可以理出AnimationController大致的工作流程。

隨著時間的流逝,插值器根據時間產生的值作為輸入,提供給估值器,產生動畫的實際效果值,結合Ticker的回撥,渲染出當前動畫值的影象。這也是補間動畫的工作原理,如下圖所示。

Flutter動畫詳解

今天介紹了這麼多Flutter動畫相關的知識,還要給大家額外送上一份私貨,自己收錄整理的

Android學習PDF+架構影片+面試文件+原始碼筆記

,還有

高階架構技術進階腦圖、Android開發面試專題資料,高階進階架構資料

幫助大家學習提升進階,也節省大家在網上搜索資料的時間來學習,也可以分享給身邊好友一起學習

如果你有需要的話,可以

點贊+評論+轉發

關注我

,然後

私信我【進階】我發給你

Flutter動畫詳解

Flutter動畫詳解

Flutter動畫詳解