動畫 API 概述
Flutter 中的動畫系統基於類型化的 Animation
物件。Widget 可以直接在它們的 build 函式中整合這些動畫,方式是讀取它們的目前值並監聽它們的狀態變化,或者它們可以使用這些動畫作為更精細動畫的基礎,並將這些動畫傳遞給其他 widget。
動畫
#動畫系統的主要建構區塊是 Animation
類別。動畫表示特定類型的值,該值可以在動畫的生命週期中改變。大多數執行動畫的 widget 會接收一個 Animation
物件作為參數,它們從該參數讀取動畫的目前值,並監聽該值的變化。
addListener
#每當動畫的值改變時,動畫會通知所有使用 addListener
新增的監聽器。通常,監聽動畫的 State
物件會在它的監聽器回呼函式中呼叫 setState
來通知 widget 系統它需要用動畫的新值重新建構。
這種模式非常常見,因此有兩個 widget 可以協助 widget 在動畫值改變時重新建構:AnimatedWidget
和 AnimatedBuilder
。第一個 AnimatedWidget
,對於無狀態的動畫 widget 最有用。要使用 AnimatedWidget
,只需繼承它並實作 build
函式。第二個 AnimatedBuilder
,對於希望將動畫包含在較大的 build 函式中的更複雜的 widget 非常有用。要使用 AnimatedBuilder
,只需建構 widget 並傳遞一個 builder
函式。
addStatusListener
#動畫還提供一個 AnimationStatus
,它指示動畫如何隨著時間推移而變化。每當動畫的狀態改變時,動畫會通知所有使用 addStatusListener
新增的監聽器。通常,動畫以 dismissed
狀態開始,這表示它們在其範圍的開頭。例如,從 0.0 到 1.0 進展的動畫,當它們的值為 0.0 時將會是 dismissed
。然後,動畫可能會 forward
執行(從 0.0 到 1.0),或者可能會 reverse
執行(從 1.0 到 0.0)。最終,如果動畫到達其範圍的末端 (1.0),則動畫會達到 completed
狀態。
AnimationController
#要建立動畫,首先要建立一個 AnimationController
。除了它本身就是一個動畫之外,AnimationController
還可以讓您控制動畫。例如,您可以告訴控制器播放動畫 forward
或 stop
動畫。您也可以 fling
動畫,它使用物理模擬(例如彈簧)來驅動動畫。
建立動畫控制器後,您可以開始基於它建立其他動畫。例如,您可以建立一個 ReverseAnimation
,它會鏡像原始動畫,但會朝相反的方向執行(從 1.0 到 0.0)。同樣地,您可以建立一個 CurvedAnimation
,其值會由 Curve
調整。
Tweens
#若要動畫超過 0.0 到 1.0 的間隔,您可以使用 Tween<T>
,它會在它的 begin
和 end
值之間進行插值。許多類型都有提供類型特定插值的特定 Tween
子類別。例如,ColorTween
會在顏色之間進行插值,而 RectTween
會在矩形之間進行插值。您可以建立自己的 Tween
子類別並覆寫其 lerp
函式,來定義您自己的插值。
單獨來說,tween 只是定義如何在兩個值之間進行插值。若要取得動畫目前影格的具體值,您還需要一個動畫來決定目前的狀態。有兩種方法可以將 tween 與動畫結合,以取得具體的值
您可以在動畫的目前值
evaluate
tween。這種方法對於已經在監聽動畫的 widget 最有用,因此每當動畫值改變時,它們都會重新建構。您可以根據動畫
animate
tween。animate
函式不是傳回單個值,而是傳回一個包含 tween 的新Animation
。當您想要將新建立的動畫提供給另一個 widget 時,此方法最有用,該 widget 隨後可以讀取包含 tween 的目前值,並監聽該值的變化。
架構
#動畫實際上是由許多核心建構區塊所組成的。
Scheduler
#SchedulerBinding
是一個 singleton 類別,它公開 Flutter 的排程基本元素。
對於此討論,關鍵基本元素是影格回呼。每次需要在螢幕上顯示影格時,Flutter 的引擎會觸發一個「開始影格」回呼,排程器會將其多工處理到所有使用 scheduleFrameCallback()
註冊的監聽器。所有這些回呼都會收到影格的官方時間戳記,格式為從某個任意紀元開始的 Duration
。由於所有回呼都具有相同的時間,因此即使它們需要幾毫秒才能執行,從這些回呼觸發的任何動畫都會顯得完全同步。
Tickers
#Ticker
類別會連線到排程器的 scheduleFrameCallback()
機制,以在每次滴答時呼叫回呼。
可以啟動和停止 Ticker
。啟動時,它會傳回一個 Future
,該 Future
將在停止時解析。
每次滴答時,Ticker
都會為回呼提供自啟動後第一次滴答以來的持續時間。
由於 ticker 始終給出相對於它們啟動後第一次滴答的經過時間;因此所有 ticker 都是同步的。如果您在兩個滴答之間的不同時間啟動三個 ticker,它們仍然會與相同的開始時間同步,並隨後鎖定步調滴答。就像公車站的人一樣,所有 ticker 都會等待定期發生的事件(滴答)開始移動(計算時間)。
Simulations
#Simulation
抽象類別會將相對時間值(經過的時間)對應到一個 double 值,並具有完成的概念。
原則上,模擬是無狀態的,但實際上某些模擬(例如,BouncingScrollSimulation
和 ClampingScrollSimulation
)在查詢時會不可逆地改變狀態。
有 Simulation
類別的各種具體實作,用於不同的效果。
Animatables
#Animatable
抽象類別會將 double 對應到特定類型的值。
Animatable
類別是無狀態且不可變的。
Tweens
#Tween<T>
抽象類別會將名義上在 0.0-1.0 範圍內的 double 值對應到類型化的值(例如,Color
或另一個 double)。它是 Animatable
。
它具有輸出類型 (T
)、該類型的 begin
值和 end
值,以及在給定輸入值(名義上在 0.0-1.0 範圍內的 double)的 begin 值和 end 值之間進行插值 (lerp
) 的方法。
Tween
類別是無狀態且不可變的。
組合動畫
#將 Animatable<double>
(父項)傳遞給 Animatable
的 chain()
方法會建立一個新的 Animatable
子類別,該子類別會先套用父項的對應,然後再套用子項的對應。
Curves
#Curve
抽象類別會將名義上在 0.0-1.0 範圍內的 double 對應到名義上在 0.0-1.0 範圍內的 double。
Curve
類別是無狀態且不可變的。
Animations
#Animation
抽象類別提供給定類型的值、動畫方向和動畫狀態的概念,以及一個監聽器介面,用於註冊在值或狀態變更時會被呼叫的回呼。
Animation
的某些子類別的值永遠不會改變 (kAlwaysCompleteAnimation
、kAlwaysDismissedAnimation
、AlwaysStoppedAnimation
);在這些子類別上註冊回呼沒有任何作用,因為永遠不會呼叫回呼。
Animation<double>
變體很特別,因為它可以用來表示名義上在 0.0-1.0 範圍內的 double,這是 Curve
和 Tween
類別以及 Animation
的某些其他子類別所期望的輸入。
某些 Animation
子類別是無狀態的,只會將監聽器轉發給其父項。有些則是非常有狀態的。
可組合的動畫
#大多數 Animation
子類別都採用一個明確的「父」Animation<double>
。它們是由該父項驅動的。
CurvedAnimation
子類別會接收一個 Animation<double>
類別(父類別)和一對 Curve
類別(正向和反向曲線)作為輸入,並使用父類別的值作為曲線的輸入,以決定其輸出。CurvedAnimation
是不可變且無狀態的。
ReverseAnimation
子類別會接收一個 Animation<double>
類別作為其父類別,並反轉動畫的所有值。它假設父類別使用範圍通常在 0.0-1.0 的值,並返回範圍在 1.0-0.0 的值。父動畫的狀態和方向也會被反轉。ReverseAnimation
是不可變且無狀態的。
ProxyAnimation
子類別會接收一個 Animation<double>
類別作為其父類別,並僅轉發該父類別的目前狀態。然而,父類別是可變的。
TrainHoppingAnimation
子類別接收兩個父類別,並在它們的值交叉時在它們之間切換。
動畫控制器
#AnimationController
是一個有狀態的 Animation<double>
,它使用 Ticker
來賦予自身生命。它可以啟動和停止。在每次 tick 時,它會取得自啟動以來經過的時間,並將其傳遞給一個 Simulation
以獲得一個值。這就是它報告的值。如果 Simulation
報告說該時間點已經結束,那麼控制器就會自行停止。
動畫控制器可以被賦予一個要動畫化的下限和上限,以及一個持續時間。
在簡單的情況下(使用 forward()
或 reverse()
),動畫控制器只會在給定的持續時間內從下限到上限(或反之,反向方向)進行線性插值。
當使用 repeat()
時,動畫控制器會在給定的持續時間內在給定的界限之間進行線性插值,但不會停止。
當使用 animateTo()
時,動畫控制器會在給定的持續時間內從目前值到給定的目標值進行線性插值。如果沒有給方法指定持續時間,則會使用控制器的預設持續時間以及控制器下限和上限所描述的範圍來確定動畫的速度。
當使用 fling()
時,會使用 Force
來建立一個特定的模擬,然後用它來驅動控制器。
當使用 animateWith()
時,會使用給定的模擬來驅動控制器。
這些方法都會傳回 Ticker
提供的 future,並且會在控制器下次停止或變更模擬時解析。
將可動畫化的物件附加到動畫
#將一個 Animation<double>
(新的父類別)傳遞給 Animatable
的 animate()
方法會建立一個新的 Animation
子類別,其行為類似於 Animatable
,但是從給定的父類別驅動。
除非另有說明,本網站上的文件反映了 Flutter 的最新穩定版本。頁面上次更新時間為 2024-04-04。 檢視原始碼 或 回報問題。