設計良好的動畫能讓 UI 更直觀,提升應用程式的精緻感,並改善使用者體驗。Flutter 的動畫支援讓你能輕鬆實作各種動畫類型。許多元件(特別是 Material 元件)都內建設計規範中定義的標準動態效果,但你也可以自訂這些效果。

選擇實作方式

#

在 Flutter 中建立動畫有多種不同的方法。哪一種方法最適合你?為了協助你判斷,請參考這部影片:How to choose which Flutter Animation Widget is right for you? (Also published as a companion article.)

Watch on YouTube in a new tab: "How to choose which Flutter animation widget is right for your use case"

(若想更深入了解決策過程,請觀看於 Flutter Europe 發表的 Animations in Flutter done right 影片。)

如影片所示,下方的決策樹能協助你決定在實作 Flutter 動畫時該採用哪種方式:

The animation decision tree

動畫深入解析

#

若想更深入了解 Flutter 動畫的運作原理,請觀看 Animation deep dive。 (同時也有 配套文章。)

Watch on YouTube in a new tab: "Take a deep dive into Flutter animation"

隱式與顯式動畫

#

預先封裝的隱式動畫

#

如果預先封裝的隱式動畫(最容易實作的動畫)能滿足你的需求,請觀看 Animation basics with implicit animations。 (同時也有 配套文章。)

Watch on YouTube in a new tab: "Flutter implicit animation basics"

自訂隱式動畫

#

若要建立自訂的隱式動畫,請觀看 Creating your own custom implicit animations with TweenAnimationBuilder。 (同時也有 配套文章。)

Watch on YouTube in a new tab: "Create custom implicit animations with TweenAnimationBuilder"

內建隱式動畫

#

若要建立顯式動畫(由你控制動畫,而非讓框架自動控制),你可以考慮使用內建的顯式動畫類別。更多資訊請觀看 Making your first directional animations with built-in explicit animations。 (同時也有 配套文章。)

Watch on YouTube in a new tab: "Making your first directional animations with built-in explicit animations"

顯式動畫

#

如果你需要從零開始建立顯式動畫,請觀看 Creating custom explicit animations with AnimatedBuilder and AnimatedWidget。 (同時也有 配套文章。)

Watch on YouTube in a new tab: "Creating custom explicit animations with AnimatedBuilder and AnimatedWidget"

動畫類型

#

一般來說,動畫可分為 Tween 型與物理模擬型。以下各節將說明這些術語的意義,並提供進一步學習的資源。

Tween 動畫

#

Tween 是 in-betweening 的簡稱。在 Tween 動畫中,你會定義起點與終點,以及時間軸與描述過渡時機和速度的曲線。框架會計算如何從起點過渡到終點。

物理模擬動畫

#

在物理模擬動畫中,動作會模擬真實世界的行為。例如你拋一顆球時,它落地的位置與時間取決於拋出的速度及離地高度。同樣地,將球綁在彈簧上掉落,與綁在繩子上掉落的運動(與彈跳)也會不同。

常見動畫模式

#

多數 UX 或動態設計師會發現,設計 UI 時有些動畫模式會反覆出現。本節列出一些常見的動畫模式,並說明可在哪裡深入學習。

動畫化清單或格狀佈局

#

這種模式會在清單或格狀佈局中,為元素的新增或移除加上動畫效果。

  • AnimatedList 範例
    這個來自 範例應用程式目錄 的展示,說明如何為清單新增元素或移除選取元素時加入動畫。當使用者透過加號(+)和減號(-)按鈕修改清單時,內部的 Dart 清單會同步更新。

共用元素轉場

#

在這種模式中,使用者會從頁面選取一個元素(通常是圖片),UI 會將該元素以動畫方式轉場到另一個包含更多細節的新頁面。在 Flutter 中,你可以使用 Hero 元件輕鬆實現路由(頁面)間的共用元素轉場。

  • Hero 動畫 如何建立兩種 Hero 動畫風格:

    • Hero 從一個頁面飛到另一個頁面,並同時改變位置與大小。
    • Hero 的邊界形狀會從圓形變為方形,並在飛行過程中完成頁面轉換。
  • 也請參閱 HeroNavigatorPageRoute 類別的 API 文件。

交錯動畫(Staggered animation)

#

交錯動畫會將動畫拆分為多個較小的動作,其中部分動作會延遲執行。這些小動畫可以是連續的,也可以部分或完全重疊。

重要動畫概念與類別

#

Flutter 的動畫系統是以型別化的 Animation 物件為基礎。元件(Widgets)可以直接在其 build 函式中讀取動畫的當前值並監聽其狀態變化,或將動畫作為更複雜動畫的基礎,傳遞給其他元件使用。

Animation<double>

#

在 Flutter 中,Animation 物件本身不關心畫面上顯示的內容。Animation 是一個抽象類別,能夠理解自己的當前值與狀態(已完成或已消失)。其中一種常用的動畫型別是 Animation<double>

Animation 物件會在一段期間內,依序產生兩個值之間的插值數字。Animation 物件的輸出可以是線性的、曲線的、階梯函數,或你能建立的任何其他對應方式。根據 Animation 物件的控制方式,它可以反向運行,甚至在中途切換方向。

動畫也可以插值 double 以外的型別,例如 Animation<Color>Animation<Size>

Animation 物件具有狀態。其當前值可隨時透過 .value 成員取得。

Animation 物件不涉及繪製(rendering)或 build() 函式。

CurvedAnimation

#

CurvedAnimation 用非線性曲線來定義動畫的進度。

dart
animation = CurvedAnimation(parent: controller, curve: Curves.easeIn);

CurvedAnimationAnimationController(在接下來的章節中會說明)都是 Animation<double> 類型,因此你可以互換傳遞它們。CurvedAnimation 會包裝它所修改的物件——你不需要透過繼承 AnimationController 來實作曲線(curve)。

你可以將 CurvesCurvedAnimation 一起使用。Curves 類別定義了許多常用的曲線(curve),你也可以自行建立。例如:

dart
import 'dart:math';

class ShakeCurve extends Curve {
  @override
  double transform(double t) => sin(t * pi * 2);
}

如果你想將動畫曲線(animation curve)應用到Tween,可以考慮使用
CurveTween

AnimationController

#

AnimationController 是一個特殊的Animation物件,會在硬體準備好新畫格時產生新數值。預設情況下,AnimationController會在指定的持續時間內,線性產生從 0.0 到 1.0 的數值。例如,以下程式碼建立了一個Animation物件,但尚未啟動它:

dart
controller = AnimationController(
  duration: const Duration(seconds: 2),
  vsync: this,
);

AnimationController 是從 Animation<double> 衍生而來,因此可以在需要 Animation 物件的地方使用。不過,AnimationController 還有額外的方法可用來控制動畫(Animation)。例如,你可以透過 .forward() 方法來啟動動畫。數值的產生與螢幕刷新率綁定,因此通常每秒會產生 60 個數值。每當產生一個數值時,每個 Animation 物件都會呼叫其附加的 Listener 物件。若要為每個子項建立自訂的顯示清單,請參考 RepaintBoundary

建立 AnimationController 時,你需要傳入一個 vsync 參數。vsync 的存在可防止螢幕外的動畫(offscreen animation)消耗不必要的資源。 你可以將你的 stateful 物件作為 vsync,只需在類別定義中加入 SingleTickerProviderStateMixin 即可。 你可以在 GitHub 上的 animate1 範例中看到這個做法。

Tween

#

預設情況下,AnimationController 物件的範圍是 0.0 到 1.0。 如果你需要不同的範圍或不同的資料型別,可以使用 Tween 來設定動畫(Animation)以插值到其他範圍或資料型別。例如,下列 Tween 的範圍是從 -200.0 到 0.0:

dart
tween = Tween<double>(begin: -200, end: 0);

Tween 是一個無狀態物件,只接收 beginendTween 的唯一工作是定義從輸入範圍到輸出範圍的對應關係。輸入範圍通常是 0.0 到 1.0,但這並非必要條件。

Tween 是從 Animatable<T> 繼承,而不是從 Animation<T> 繼承。 Animatable,就像 Animation 一樣,輸出的不一定是 double。 例如,ColorTween 指定了兩種顏色之間的漸變過程。

dart
colorTween = ColorTween(begin: Colors.transparent, end: Colors.black54);

Tween 物件本身不會儲存任何狀態。相反地,它提供了 evaluate(Animation<double> animation) 方法,該方法會使用 transform 函式,將動畫 (Animation) 當前的值(介於 0.0 到 1.0 之間)對應到實際的動畫值。

Animation 物件的當前值可以透過 .value 方法取得。evaluate 函式同時也會進行一些管理工作,例如確保當動畫值分別為 0.0 和 1.0 時,會正確回傳 begin 與 end。

Tween.animate

#

若要使用 Tween 物件,請在 Tween 上呼叫 animate(),並傳入控制器物件。例如,下列程式碼會在 500 毫秒內產生從 0 到 255 的整數值。

dart
AnimationController controller = AnimationController(
  duration: const Duration(milliseconds: 500),
  vsync: this,
);
Animation<int> alpha = IntTween(begin: 0, end: 255).animate(controller);

以下範例展示了一個控制器(controller)、一個曲線(curve),以及一個 Tween

dart
AnimationController controller = AnimationController(
  duration: const Duration(milliseconds: 500),
  vsync: this,
);
final Animation<double> curve = CurvedAnimation(
  parent: controller,
  curve: Curves.easeOut,
);
Animation<int> alpha = IntTween(begin: 0, end: 255).animate(curve);

動畫通知

#

一個 Animation 物件可以擁有 ListenerStatusListener, 分別透過 addListener()addStatusListener() 來定義。 每當動畫的值發生變化時,Listener 會被呼叫。 Listener 最常見的行為是呼叫 setState() 以觸發重新建構(rebuild)。 當動畫開始、結束、向前移動或反向移動時,會根據 AnimationStatus 呼叫 StatusListener

Codelabs、教學與文章

#

以下資源是學習 Flutter 動畫(Animation)框架的好起點。每一份文件都展示了如何撰寫動畫程式碼。

  • 隱式動畫 codelab

    透過逐步說明與互動範例,介紹如何使用隱式動畫。

  • 動畫教學

    說明 Flutter 動畫套件中的基本類別 (控制器、Animatable、曲線、監聽器、建構器), 並引導你透過不同動畫 API 實現一系列 Tween 動畫。 此教學也會展示如何自訂明確動畫(explicit animation)。

  • Zero to One with Flutter, part 1part 2

    Medium 文章,展示如何透過 Tweening 製作動畫圖表。

  • Casual games toolkit

    一套包含遊戲範本的工具包,內含如何使用 Flutter 動畫的範例。

其他資源

#

你可以透過以下連結進一步了解 Flutter 動畫: