Jetpack Compose自定義動畫與Animatable詳解
本篇主要是自定義動畫與Animatable。
AnimationSpec
上一篇中,出現(xiàn)了多次animationSpec屬性,它是用來自定義動畫規(guī)范的。例如:
fun Modifier.animateContentSize(
animationSpec: FiniteAnimationSpec<IntSize> = spring(),
finishedListener: ((initialValue: IntSize, targetValue: IntSize) -> Unit)? = null
): Modifier
下面是幾種自帶的動畫規(guī)范:
1.spring
我們上一篇也簡單說到了,它是一種彈性動畫。源碼如下:
@Stable
fun <T> spring(
dampingRatio: Float = Spring.DampingRatioNoBouncy,
stiffness: Float = Spring.StiffnessMedium,
visibilityThreshold: T? = null
): SpringSpec<T> = SpringSpec(dampingRatio, stiffness, visibilityThreshold)
dampingRatio: 定義彈簧的彈性,數(shù)值越小彈性越高。默認值DampingRatioNoBouncy為1f。下圖為其他數(shù)值的效果:

stiffness: 定義彈簧向結(jié)束值移動的速度。默認值StiffnessMedium為1500f。visibilityThreshold:可見臨界值(動畫停止的值)。比如目標150dp,此值設置10dp,那么回彈距離小于這個值時就會停止彈性效果。
2.tween
在指定的時間內(nèi)使用緩和曲線在起始值和結(jié)束值之間添加動畫效果。
@Stable
fun <T> tween(
durationMillis: Int = DefaultDurationMillis,
delayMillis: Int = 0,
easing: Easing = FastOutSlowInEasing
): TweenSpec<T> = TweenSpec(durationMillis, delayMillis, easing)
val FastOutSlowInEasing: Easing = CubicBezierEasing(0.4f, 0.0f, 0.2f, 1.0f)durationMillis:動畫的持續(xù)時間,默認值300毫秒。delayMillis:延遲動畫開始的時間。easing:兩個值之間的插值曲線,類似Android中的Interpolator插值器。目前compose中提供了五種類型,這里就不一一說明了,實際使用時可以嘗試一下。當然你也可以使用CubicBezierEasing甚至Easing自定義曲線。
3.keyframes
在動畫時長內(nèi)的不同時間戳中指定快照值,實現(xiàn)動畫效果。在任何給定時間,動畫值都將插值到兩個關(guān)鍵幀值之間。對于其中每個關(guān)鍵幀,您都可以指定 Easing 來確定插值曲線。
@Stable
fun <T> keyframes(
init: KeyframesSpec.KeyframesSpecConfig<T>.() -> Unit
): KeyframesSpec<T> {
return KeyframesSpec(KeyframesSpec.KeyframesSpecConfig<T>().apply(init))
}例子:
val value by animateFloatAsState(
targetValue = 1f,
animationSpec = keyframes {
durationMillis = 375
0.0f at 0 with LinearOutSlowInEasing // for 0-15 ms
0.2f at 15 with FastOutLinearInEasing // for 15-75 ms
0.4f at 75 // ms
0.4f at 225 // ms
}
)解釋一下上面的例子:整體起始值0和結(jié)束值1,動畫時長375毫秒。
- 從0開始到0.2結(jié)束,前15毫秒使用
LinearOutSlowInEasing過渡。 - 從0.2開始到0.4結(jié)束,15到75毫秒使用
FastOutLinearInEasing過渡。 - 從0.4開始到0.4結(jié)束,75到225毫秒勻速過渡。(靜止效果)
- 從0.4開始到1結(jié)束,225毫秒到結(jié)束勻速過渡。
效果圖如下:

keyframes同樣也可以設置delayMillis指定延時時間。
4.repeatable
重復運行基于時長的動畫,直至達到指定的迭代計數(shù)。
@Stable
fun <T> repeatable(
iterations: Int,
animation: DurationBasedAnimationSpec<T>,
repeatMode: RepeatMode = RepeatMode.Restart,
initialStartOffset: StartOffset = StartOffset(0)
): RepeatableSpec<T> = RepeatableSpec(iterations, animation, repeatMode, initialStartOffset)
iterations,動畫運行的次數(shù)。1表示不重復。建議使用infiniteRepeatable創(chuàng)建無限重復的動畫。animation,設置需要重復的動畫。repeatMode,重復模式。指定動畫是從頭開始 (RepeatMode.Restart) 還是從結(jié)尾開始 (RepeatMode.Reverse) 重復播放。initialStartOffset,可用于延遲動畫的開始或快進動畫到給定的播放時間。如果設置StartOffset(1500)就是延遲動畫。 設置StartOffset(1500, offsetType = StartOffsetType.FastForward)就是快進動畫。默認情況下,延時時長為0。
如果需要動畫重復無限次,可以使用infiniteRepeatable,用法與repeatable一致。
5.snap
snap是特殊的 AnimationSpec,它會立即將值切換到結(jié)束值。您可以指定 delayMillis 來延遲動畫播放的開始時間。
@Stable fun <T> snap(delayMillis: Int = 0) = SnapSpec<T>(delayMillis)
Animatable
Animatable 是一個值容器,它可以在通過 animateTo 更改值時為值添加動畫效果。它可確保一致的連續(xù)性和互斥性,這意味著值變化始終是連續(xù)的,并且會取消任何正在播放的動畫。
Animatable 的許多功能(包括 animateTo)以掛起函數(shù)的形式提供。這意味著,它們需要封裝在適當?shù)膮f(xié)程作用域內(nèi)。例如,您可以使用 LaunchedEffect 可組合項針對指定鍵值的時長創(chuàng)建一個作用域。
// Start out gray and animate to green/red based on `ok`
val color = remember { Animatable(Color.Gray) }
LaunchedEffect(ok) {
color.animateTo(if (ok) Color.Green else Color.Red)
}
Box(Modifier.fillMaxSize().background(color.value))
在上面的示例中,我們創(chuàng)建并記住了初始值為 Color.Gray 的 Animatable 實例。根據(jù)布爾標記 ok 的值,顏色將以動畫形式呈現(xiàn) Color.Green 或 Color.Red。對該布爾值的任何后續(xù)更改都會使動畫開始使用另一種顏色。如果更改該值時有正在播放的動畫,系統(tǒng)會取消該動畫,并且新動畫將以當前速度從當前快照值開始播放。
與 animate*AsState 相比,使用 Animatable 可以直接對以下幾個方面進行更精細的控制。首先,Animatable 的初始值可以與第一個目標值不同。例如,上面的代碼示例首先顯示一個灰色框,然后立即開始通過動畫呈現(xiàn)為綠色或紅色。其次,Animatable 對內(nèi)容值提供更多操作(即 snapTo 和 animateDecay)。snapTo 可立即將當前值設為目標值。如果動畫本身不是唯一的可信來源,且必須與其他狀態(tài)(如觸摸事件)同步,該函數(shù)就非常有用。animateDecay 用于啟動播放從給定速度變慢的動畫(衰減)。這有助于實現(xiàn)投擲行為。
下面看一個官方demo:
Column(modifier = Modifier.fillMaxWidth()) {
// Creates an `Animatable` to animate Offset and `remember` it.
val animatedOffset = remember { Animatable(Offset(0f, 0f), Offset.VectorConverter) }
Box(
Modifier.fillMaxSize().background(Color(0xffb99aff)).pointerInput(Unit) {
coroutineScope {
while (true) {
val offset = awaitPointerEventScope {
awaitFirstDown().position
}
// Launch a new coroutine for animation so the touch detection thread is not
// blocked.
launch {
// Animates to the pressed position, with the given animation spec.
animatedOffset.animateTo(
offset,
animationSpec = spring(stiffness = Spring.StiffnessLow)
)
}
}
}
}
) {
Text("Tap anywhere", Modifier.align(Alignment.Center))
Box(
Modifier
.offset {
// Use the animated offset as the offset of the Box.
IntOffset(
animatedOffset.value.x.roundToInt(),
animatedOffset.value.y.roundToInt()
)
}
.size(40.dp)
.background(Color(0xff3c1361), CircleShape)
)
}
}效果圖這里我就不放了。就是頁面上有個40*40dp的圓形view,點擊屏幕任意位置,他就會移動過去。這里核心靠的就是animateTo方法,而且無論我們中間如果快速點擊不同位置,系統(tǒng)會取消上一個動畫,接著當前位置移動到目標位置。

從上面這張圖可以看出各個API之間的關(guān)系。所有這些 API 都基于更基礎(chǔ)的 Animation API。雖然大多數(shù)應用不會直接使用 Animation ,但 Animation 的某些自定義功能可以通過更高級別的 API 獲得。
到此,Compose的動畫部分大體結(jié)束。
參考
到此這篇關(guān)于Jetpack Compose自定義動畫與Animatable詳解的文章就介紹到這了,更多相關(guān)Jetpack Compose自定義動畫內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android實現(xiàn)網(wǎng)易新聞客戶端側(cè)滑菜單(1)
這篇文章主要為大家詳細介紹了Android實現(xiàn)網(wǎng)易新聞客戶端側(cè)滑菜單第一篇,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-11-11
Android基于google Zxing實現(xiàn)各類二維碼掃描效果
這篇文章主要介紹了Android基于google Zxing實現(xiàn)各類二維碼掃描效果的相關(guān)資料,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-02-02
Android開發(fā)中synchronized的三種使用方式詳解
這篇文章主要介紹了Android開發(fā)中synchronized的三種使用方式,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習吧2023-04-04
Android使用ViewPager實現(xiàn)啟動引導頁效果
這篇文章主要為大家詳細介紹了Android使用ViewPager實現(xiàn)啟動引導頁效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-04-04
詳解android在mob平臺實現(xiàn)qq登陸和分享
這篇文章主要介紹了詳解android在mob平臺實現(xiàn)qq登陸和分享,對接入第三方平臺SDK感興趣的同學們,可以參考下2021-04-04
Android 仿抖音的評論列表的UI和效果的實現(xiàn)代碼
抖音是一款音樂創(chuàng)意短視頻社交軟件,此app已在android各大應用商店和app store 上線。下面小編給大家?guī)砹薃ndroid 仿抖音的評論列表的UI和效果的實現(xiàn)代碼,感興趣的朋友參考下吧2018-03-03

