跳到主內容

動畫簡介

如何在 Flutter 中實現動畫。

精心設計的動畫能讓使用者介面(UI)更直觀,為應用帶來流暢且精緻的視覺體驗,從而提升整體使用者體驗。Flutter 的動畫支援使得實現各種型別的動畫變得非常容易。許多元件,特別是 Material 元件,都內建了設計規範中定義的標準運動效果,當然你也可以自定義這些效果。

選擇動畫實現方式

#

在 Flutter 中建立動畫時,有多種途徑可選。哪種方式最適合你?為了幫助你做出決定,請觀看影片:如何選擇適合你的 Flutter 動畫元件?(本文亦以配套文章形式釋出。)

在 YouTube 新標籤頁中觀看:“如何選擇適合你用例的 Flutter 動畫元件”

(欲深入瞭解決策過程,請觀看在 Flutter Europe 上發表的影片:Flutter 動畫的正確實現方式。)

正如影片所示,以下決策樹可以幫助你確定在實現 Flutter 動畫時應使用哪種方法

The animation decision tree

動畫深度解析

#

如需深入瞭解 Flutter 動畫的工作原理,請觀看動畫深度解析。(亦有配套文章。)

在 YouTube 新標籤頁中觀看:“深入探索 Flutter 動畫”

隱式與顯式動畫

#

預封裝的隱式動畫

#

如果預封裝的隱式動畫(最容易實現的動畫)符合你的需求,請觀看隱式動畫基礎。(亦有配套文章。)

在 YouTube 新標籤頁中觀看:“Flutter 隱式動畫基礎”

自定義隱式動畫

#

若要建立自定義隱式動畫,請觀看使用 TweenAnimationBuilder 建立自定義隱式動畫。(亦有配套文章。)

在 YouTube 新標籤頁中觀看:“使用 TweenAnimationBuilder 建立自定義隱式動畫”

內建顯式動畫

#

若要建立顯式動畫(由你而不是框架來控制動畫),你可以考慮使用內建的顯式動畫類。更多資訊,請觀看透過內建顯式動畫製作你的第一個定向動畫。(亦有配套文章。)

在 YouTube 新標籤頁中觀看:“透過內建顯式動畫製作你的第一個定向動畫”

顯式動畫

#

如果需要從零開始構建顯式動畫,請觀看使用 AnimatedBuilder 和 AnimatedWidget 建立自定義顯式動畫。(亦有配套文章。)

在 YouTube 新標籤頁中觀看:“使用 AnimatedBuilder 和 AnimatedWidget 建立自定義顯式動畫”

動畫型別

#

通常,動畫分為補間(Tween)動畫和基於物理的動畫。以下部分解釋了這些術語的含義,並提供了進一步學習的資源。

補間(Tween)動畫

#

“補間”是 in-betweening 的縮寫。在補間動畫中,不僅要定義開始和結束點,還要定義時間線,以及決定過渡時機和速度的曲線。框架會自動計算從起點到終點的過渡方式。

基於物理的動畫

#

在基於物理的動畫中,運動被模擬為接近現實世界的行為。例如,當你丟擲一個球時,球落下的位置和時間取決於丟擲的速度以及距離地面的高度。同樣,掛在彈簧上的球落下(和彈起)的方式與掛在繩子上的球落下是不同的。

常見動畫模式

#

大多數 UX 或動效設計師都會發現某些動畫模式在設計 UI 時會被反覆使用。本節列出了一些常見的動畫模式,並指引你深入瞭解它們。

動畫列表或網格

#

此模式涉及對列表或網格中元素的新增或移除進行動畫處理。

  • AnimatedList 示例
    此演示來自 示例應用庫,展示瞭如何為向列表新增元素或移除選定元素新增動畫。當用戶使用加號 (+) 和減號 (-) 按鈕修改列表時,內部的 Dart 列表會同步更新。

共享元素過渡

#

在此模式下,使用者從頁面中選擇一個元素(通常是圖片),UI 將選中的元素以動畫形式過渡到包含更多詳情的新頁面。在 Flutter 中,你可以使用 Hero 元件輕鬆實現路由(頁面)之間的共享元素過渡。

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

    • Hero 元素在頁面間飛行時同時改變位置和大小。
    • Hero 元素的邊界在從一個頁面飛往另一個頁面時改變形狀,例如從圓形變為方形。
  • 另請參閱 HeroNavigatorPageRoute 類的 API 文件。

交錯動畫

#

將動畫分解為較小的運動,其中部分運動存在延遲。這些較小的動畫可以是順序的,也可以是部分或完全重疊的。

動畫核心概念與類

#

Flutter 的動畫系統基於型別化的 Animation 物件。元件既可以在構建函式(build function)中透過讀取其當前值並監聽狀態變化來直接合並這些動畫,也可以將它們作為更復雜動畫的基礎,再傳遞給其他元件。

Animation<double>

#

在 Flutter 中,Animation 物件本身並不瞭解螢幕上的具體內容。Animation 是一個抽象類,它瞭解其當前值和狀態(已完成或已取消)。最常用的動畫型別之一是 Animation<double>

Animation 物件會在特定持續時間內順序生成兩個值之間的插值數字。Animation 物件的輸出可以是線性的、曲線的、階梯函式,或任何你可以建立的對映。取決於 Animation 物件的控制方式,它還可以反向執行,甚至在中間改變方向。

動畫還可以對除 double 以外的型別進行插值,例如 Animation<Color>Animation<Size>

Animation 物件具有狀態。其當前值始終可以透過 .value 成員獲取。

Animation 物件本身不涉及渲染或 build() 函式。

CurvedAnimation

#

CurvedAnimation 將動畫的進度定義為非線性曲線。

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

CurvedAnimationAnimationController(將在下一節描述)都是 Animation<double> 型別,因此可以互換使用。CurvedAnimation 會包裝它所修改的物件——你不需要透過子類化 AnimationController 來實現曲線效果。

你可以結合 CurvedAnimation 使用 CurvesCurves 類定義了許多常用的曲線,你也可以建立自己的曲線。例如:

dart
import 'dart:math';

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

如果你想對 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 具有額外的方法來控制動畫。例如,你可以透過 .forward() 方法開始動畫。數字的生成與螢幕重新整理同步,因此通常每秒生成 60 個數字。在每個數字生成後,每個 Animation 物件都會呼叫附加的 Listener 物件。若要為每個子元件建立自定義顯示列表,請參考 RepaintBoundary

建立 AnimationController 時,需要傳入 vsync 引數。vsync 的存在可以防止螢幕外的動畫消耗不必要的資源。你可以透過在類定義中新增 SingleTickerProviderStateMixin 來將當前有狀態物件作為 vsync 使用。你可以在 GitHub 上的 animate1 示例中檢視具體用法。

Tween

#

預設情況下,AnimationController 物件的範圍從 0.0 到 1.0。如果需要不同的範圍或不同的資料型別,可以使用 Tween 來配置動畫,以插值到不同的範圍或資料型別。例如,以下 Tween 從 -200.0 到 0.0:

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

Tween 是一個無狀態物件,僅包含 beginendTween 的唯一職責是定義從輸入範圍到輸出範圍的對映。輸入範圍通常是 0.0 到 1.0,但這不是必需的。

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

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

Tween 物件不儲存任何狀態。相反,它提供了 evaluate(Animation<double> animation) 方法,該方法使用 transform 函式將動畫的當前值(介於 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);

以下示例展示了一個控制器、一個曲線和一個 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() 來觸發重建。當動畫開始、結束、向前移動或向後移動時(由 AnimationStatus 定義),StatusListener 會被呼叫。

Codelabs、教程和文章

#

以下資源是開始學習 Flutter 動畫框架的良好起點。每份文件都展示瞭如何編寫動畫程式碼。

  • Flutter 動畫 Codelab
    在構建多項選擇測驗遊戲的同時,學習隱式和顯式動畫。

  • 動畫教程
    解釋了 Flutter 動畫包中的基本類(控制器、Animatable、曲線、監聽器、構建器),並引導你完成一系列使用不同動畫 API 的補間動畫。本教程展示瞭如何建立自定義顯式動畫。

  • Flutter 從零到一,第一部分第二部分
    Medium 文章,展示如何使用補間製作動畫圖表。

  • 休閒遊戲工具包
    包含遊戲模板的工具包,其中包含如何使用 Flutter 動畫的示例。

其他資源

#

透過以下連結瞭解更多關於 Flutter 動畫的資訊: