動畫簡介
如何在 Flutter 中實現動畫。
精心設計的動畫能讓使用者介面(UI)更直觀,為應用帶來流暢且精緻的視覺體驗,從而提升整體使用者體驗。Flutter 的動畫支援使得實現各種型別的動畫變得非常容易。許多元件,特別是 Material 元件,都內建了設計規範中定義的標準運動效果,當然你也可以自定義這些效果。
選擇動畫實現方式
#在 Flutter 中建立動畫時,有多種途徑可選。哪種方式最適合你?為了幫助你做出決定,請觀看影片:如何選擇適合你的 Flutter 動畫元件?(本文亦以配套文章形式釋出。)
(欲深入瞭解決策過程,請觀看在 Flutter Europe 上發表的影片:Flutter 動畫的正確實現方式。)
正如影片所示,以下決策樹可以幫助你確定在實現 Flutter 動畫時應使用哪種方法
動畫深度解析
#如需深入瞭解 Flutter 動畫的工作原理,請觀看動畫深度解析。(亦有配套文章。)
隱式與顯式動畫
#預封裝的隱式動畫
#如果預封裝的隱式動畫(最容易實現的動畫)符合你的需求,請觀看隱式動畫基礎。(亦有配套文章。)
自定義隱式動畫
#若要建立自定義隱式動畫,請觀看使用 TweenAnimationBuilder 建立自定義隱式動畫。(亦有配套文章。)
內建顯式動畫
#若要建立顯式動畫(由你而不是框架來控制動畫),你可以考慮使用內建的顯式動畫類。更多資訊,請觀看透過內建顯式動畫製作你的第一個定向動畫。(亦有配套文章。)
顯式動畫
#如果需要從零開始構建顯式動畫,請觀看使用 AnimatedBuilder 和 AnimatedWidget 建立自定義顯式動畫。(亦有配套文章。)
動畫型別
#通常,動畫分為補間(Tween)動畫和基於物理的動畫。以下部分解釋了這些術語的含義,並提供了進一步學習的資源。
補間(Tween)動畫
#“補間”是 in-betweening 的縮寫。在補間動畫中,不僅要定義開始和結束點,還要定義時間線,以及決定過渡時機和速度的曲線。框架會自動計算從起點到終點的過渡方式。
-
請參閱動畫教程,其中示例使用了補間動畫。
-
另請參閱
Tween、CurveTween和TweenSequence的 API 文件。
基於物理的動畫
#在基於物理的動畫中,運動被模擬為接近現實世界的行為。例如,當你丟擲一個球時,球落下的位置和時間取決於丟擲的速度以及距離地面的高度。同樣,掛在彈簧上的球落下(和彈起)的方式與掛在繩子上的球落下是不同的。
-
使用物理模擬來為元件新增動畫
Flutter Cookbook 動畫部分的示例方案。 -
另請參閱
AnimationController.animateWith和SpringSimulation的 API 文件。
常見動畫模式
#大多數 UX 或動效設計師都會發現某些動畫模式在設計 UI 時會被反覆使用。本節列出了一些常見的動畫模式,並指引你深入瞭解它們。
動畫列表或網格
#此模式涉及對列表或網格中元素的新增或移除進行動畫處理。
-
AnimatedList示例
此演示來自 示例應用庫,展示瞭如何為向列表新增元素或移除選定元素新增動畫。當用戶使用加號 (+) 和減號 (-) 按鈕修改列表時,內部的 Dart 列表會同步更新。
共享元素過渡
#在此模式下,使用者從頁面中選擇一個元素(通常是圖片),UI 將選中的元素以動畫形式過渡到包含更多詳情的新頁面。在 Flutter 中,你可以使用 Hero 元件輕鬆實現路由(頁面)之間的共享元素過渡。
-
Hero 動畫 如何建立兩種風格的 Hero 動畫
- Hero 元素在頁面間飛行時同時改變位置和大小。
- Hero 元素的邊界在從一個頁面飛往另一個頁面時改變形狀,例如從圓形變為方形。
交錯動畫
#將動畫分解為較小的運動,其中部分運動存在延遲。這些較小的動畫可以是順序的,也可以是部分或完全重疊的。
動畫核心概念與類
#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 將動畫的進度定義為非線性曲線。
animation = CurvedAnimation(parent: controller, curve: Curves.easeIn);
CurvedAnimation 和 AnimationController(將在下一節描述)都是 Animation<double> 型別,因此可以互換使用。CurvedAnimation 會包裝它所修改的物件——你不需要透過子類化 AnimationController 來實現曲線效果。
你可以結合 CurvedAnimation 使用 Curves。Curves 類定義了許多常用的曲線,你也可以建立自己的曲線。例如:
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 物件,但不會立即執行:
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:
tween = Tween<double>(begin: -200, end: 0);
Tween 是一個無狀態物件,僅包含 begin 和 end。Tween 的唯一職責是定義從輸入範圍到輸出範圍的對映。輸入範圍通常是 0.0 到 1.0,但這不是必需的。
Tween 繼承自 Animatable<T>,而不是 Animation<T>。與 Animation 一樣,Animatable 的輸出不必是 double 型別。例如,ColorTween 指定了兩種顏色之間的漸變過程。
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 的整數值:
AnimationController controller = AnimationController(
duration: const Duration(milliseconds: 500),
vsync: this,
);
Animation<int> alpha = IntTween(begin: 0, end: 255).animate(controller);
以下示例展示了一個控制器、一個曲線和一個 Tween 的結合使用:
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 物件可以擁有 Listener 和 StatusListener,它們分別透過 addListener() 和 addStatusListener() 定義。當動畫值發生變化時,Listener 會被呼叫。Listener 最常見的行為是呼叫 setState() 來觸發重建。當動畫開始、結束、向前移動或向後移動時(由 AnimationStatus 定義),StatusListener 會被呼叫。
Codelabs、教程和文章
#以下資源是開始學習 Flutter 動畫框架的良好起點。每份文件都展示瞭如何編寫動畫程式碼。
-
Flutter 動畫 Codelab
在構建多項選擇測驗遊戲的同時,學習隱式和顯式動畫。 -
動畫教程
解釋了 Flutter 動畫包中的基本類(控制器、Animatable、曲線、監聽器、構建器),並引導你完成一系列使用不同動畫 API 的補間動畫。本教程展示瞭如何建立自定義顯式動畫。 -
Flutter 從零到一,第一部分 和 第二部分
Medium 文章,展示如何使用補間製作動畫圖表。 -
休閒遊戲工具包
包含遊戲模板的工具包,其中包含如何使用 Flutter 動畫的示例。
其他資源
#透過以下連結瞭解更多關於 Flutter 動畫的資訊: