許多 Animation API 通常都接受參數來自訂動畫行為。
使用 AnimationSpec 參數自訂動畫
多數的動畫 API 都允許開發人員透過選用的 AnimationSpec 參數來自訂動畫規格。
val alpha: Float by animateFloatAsState( targetValue = if (enabled) 1f else 0.5f, // Configure the animation duration and easing. animationSpec = tween(durationMillis = 300, easing = FastOutSlowInEasing), label = "alpha" )
AnimationSpec 有多種類型,可用於建立不同類型的動畫。
使用 spring 建立以物理為基礎的動畫
spring 可在起始值和結束值之間建立以物理特性為基礎的動畫,並接受 2 個參數:dampingRatio 和 stiffness。
dampingRatio 可定義彈簧的彈性,預設值為 Spring.DampingRatioNoBouncy。
stiffness 可定義彈簧朝結束值移動的速度,預設值為 Spring.StiffnessMedium。
val value by animateFloatAsState( targetValue = 1f, animationSpec = spring( dampingRatio = Spring.DampingRatioHighBouncy, stiffness = Spring.StiffnessMedium ), label = "spring spec" )
與以持續時間為基礎的 AnimationSpec 類型相比,spring 可在目標值於動畫期間發生變化時確保速率的持續性,因此能更順暢地處理中斷情形。許多動畫 API (例如 animate*AsState 和 updateTransition) 會使用 spring 做為預設的 AnimationSpec。
舉例來說,如果我們將 spring 設定套用至下列由使用者觸控驅動的動畫,當動畫進行中遭到中斷時,您會發現使用 tween 的回應不如使用 spring 流暢。
tween 與 spring 規格,以及中斷動畫。使用 tween,透過緩和曲線在起始值和結束值之間建立動畫效果
tween 會使用緩和曲線,透過指定的 durationMillis 於起始值和結束值之間建立動畫效果。tween 是「between」(介於) 一字的縮寫,表示介於兩個值之間。
您也可以指定 delayMillis 來延遲動畫的開始時間。
val value by animateFloatAsState( targetValue = 1f, animationSpec = tween( durationMillis = 300, delayMillis = 50, easing = LinearOutSlowInEasing ), label = "tween delay" )
詳情請參閱「Easing」。
使用 keyframes 在特定時間點為特定值建立動畫
keyframes 會根據動畫期間不同時間戳記中指定的快照值建立動畫效果。在任何指定的時間,系統會在兩個主要畫面格值之間內插動畫值。針對對每個主要畫面格,都能指定 Easing 來決定內插曲線。
您可以選擇將在 0 毫秒和持續時間處指定值。如果不指定這些值,這些值會分別預設為動畫的起始值和結束值。
val value by animateFloatAsState( targetValue = 1f, animationSpec = keyframes { durationMillis = 375 0.0f at 0 using LinearOutSlowInEasing // for 0-15 ms 0.2f at 15 using FastOutLinearInEasing // for 15-75 ms 0.4f at 75 // ms 0.4f at 225 // ms }, label = "keyframe" )
使用 keyframesWithSplines 在主要畫面格之間順暢地製作動畫
如要建立動畫,在值之間轉換時沿著平滑曲線移動,可以使用 keyframesWithSplines,而非 keyframes 動畫規格。
val offset by animateOffsetAsState( targetValue = Offset(300f, 300f), animationSpec = keyframesWithSpline { durationMillis = 6000 Offset(0f, 0f) at 0 Offset(150f, 200f) atFraction 0.5f Offset(0f, 100f) atFraction 0.7f } )
以 Spline 為基礎的影格特別適合用於螢幕上項目的 2D 動作。
下列影片顯示在同一組 x、y 座標 (圓形應遵循的座標) 下,keyframes 和 keyframesWithSpline 之間的差異。
keyframes
|
keyframesWithSplines
|
|---|---|
如您所見,以 Spline 為基礎的主要畫面格可提供更平滑的點之間轉換,因為這類主要畫面格會使用貝茲曲線,在項目之間平滑地製作動畫。這項規格適用於預設動畫。不過,如果處理的是使用者驅動的點,建議使用彈簧在點之間實現類似的平滑度,因為這些點可中斷。
使用 repeatable 重複播放動畫
repeatable 會重複執行以持續時間為基礎的動畫 (例如 tween 或 keyframes),直到達到指定的疊代次數為止。您可以傳遞 repeatMode 參數以指定是否應該從開始 (RepeatMode.Restart) 或結束 (RepeatMode.Reverse) 開始重複播放動畫。
val value by animateFloatAsState( targetValue = 1f, animationSpec = repeatable( iterations = 3, animation = tween(durationMillis = 300), repeatMode = RepeatMode.Reverse ), label = "repeatable spec" )
使用 infiniteRepeatable 無限重複播放動畫
infiniteRepeatable 與 repeatable 類似,但會重複無限次的疊代。
val value by animateFloatAsState( targetValue = 1f, animationSpec = infiniteRepeatable( animation = tween(durationMillis = 300), repeatMode = RepeatMode.Reverse ), label = "infinite repeatable" )
在使用 ComposeTestRule 的測試中,系統不會執行使用 infiniteRepeatable 的動畫,而會使用每個動畫值的初始值來轉譯這個元件。
使用 snap 立即貼齊結束值
snap 是一種特殊的 AnimationSpec,可將值立即切換到結束值。您可以指定 delayMillis 以便延遲動畫的開始時間。
val value by animateFloatAsState( targetValue = 1f, animationSpec = snap(delayMillis = 50), label = "snap spec" )
設定自訂緩和函式
以持續時間為基礎的 AnimationSpec 作業 (例如 tween 或 keyframes) 會使用 Easing 來調整動畫的分數。如此一來,動畫值就能加速或減速,而不是以固定速率移動。分數是介於 0 (起始) 和 1.0 (結束) 之間的值,表示動畫中的目前點。
Easing 實際上是一種函式,可接受介於 0 和 1.0 之間的分數值並傳回浮點值。傳回的值可能在範圍邊界外,代表過衝或是下衝。您可以建立自訂的 Easing,如以下程式碼所示。
val CustomEasing = Easing { fraction -> fraction * fraction } @Composable fun EasingUsage() { val value by animateFloatAsState( targetValue = 1f, animationSpec = tween( durationMillis = 300, easing = CustomEasing ), label = "custom easing" ) // …… }
Compose 提供多種內建 Easing 函式,可滿足大多數用途的需求。如要進一步瞭解如何根據您的情境使用哪些 Easing,請參閱「速度 - 質感設計」。
FastOutSlowInEasingLinearOutSlowInEasingFastOutLinearEasingLinearEasingCubicBezierEasing- 顯示更多資訊
將自訂資料類型轉換為 AnimationVector,即可製作動畫
多數 Compose 動畫 API 皆支援 Float、Color、Dp 和其他基本資料類型做為預設動畫值,但有時您需要為其他資料類型 (包括您的自訂類型) 建立動畫。在動畫播放期間,任何動畫值都會以 AnimationVector 表示。使用對應的 TwoWayConverter 即可將值轉換為 AnimationVector,反之亦然。這樣以來,核心動畫系統就能統一處理這些內容。舉例來說,Int 是以包含單一浮點值的 AnimationVector1D 代表。「Int」的「TwoWayConverter」看起來會像是這樣:
val IntToVector: TwoWayConverter<Int, AnimationVector1D> = TwoWayConverter({ AnimationVector1D(it.toFloat()) }, { it.value.toInt() })
基本上,Color 是紅色、綠色、藍色和 alpha 這 4 個值的組合,因此 Color 可轉換成包含 4 個浮點值的 AnimationVector4D。透過這種方式,動畫中使用的每種資料類型都會轉換成 AnimationVector1D、AnimationVector2D、AnimationVector3D 或 AnimationVector4D,視其維度而定。如此一來,您就能針對物件的不同元件個別建立動畫效果,而每個元件都有各自的速率追蹤。基本資料類型的內建轉換器可使用 Color.VectorConverter 或 Dp.VectorConverter 等轉換器存取。
如要想要為新的資料類型新增支援以作為動畫值,您可以建立專屬的 TwoWayConverter 並將其提供給 API。舉例來說,您可以使用 animateValueAsState 為自訂資料類型建立動畫效果,如下所示:
data class MySize(val width: Dp, val height: Dp) @Composable fun MyAnimation(targetSize: MySize) { val animSize: MySize by animateValueAsState( targetSize, TwoWayConverter( convertToVector = { size: MySize -> // Extract a float value from each of the `Dp` fields. AnimationVector2D(size.width.value, size.height.value) }, convertFromVector = { vector: AnimationVector2D -> MySize(vector.v1.dp, vector.v2.dp) } ), label = "size" ) }
以下列出一些內建的 VectorConverter:
Color.VectorConverterDp.VectorConverterOffset.VectorConverterInt.VectorConverterFloat.VectorConverterIntSize.VectorConverter
為您推薦
- 注意:系統會在 JavaScript 關閉時顯示連結文字
- 以價值為準的動畫
- 疊代程式碼開發 {:#iterative-code-dev }
- Compose 中的動畫