Jetpack Compose實(shí)現(xiàn)動(dòng)畫(huà)效果的方法詳解
概述
compose 為支持動(dòng)畫(huà)提供了大量的 api,通過(guò)這些 api 我們可以輕松實(shí)現(xiàn)動(dòng)畫(huà)效果
ps:這些 api 的原理與 Flutter 很接近,與原生的 api 相去甚遠(yuǎn)
你可以提前看看用 compose 實(shí)現(xiàn)的一個(gè)放大縮小動(dòng)畫(huà),總的來(lái)說(shuō)還是比較流暢:

低級(jí)別動(dòng)畫(huà) API
animate*AsState
所能處理屬性的種類(lèi):Float、Color、Dp、Size、Bounds、Offset、Rect、Int、IntOffset 和 IntSize
通過(guò) animate*AsState 我們可以實(shí)現(xiàn)單一屬性的動(dòng)畫(huà)效果,我們只需要提供目標(biāo)值就可以自動(dòng)從當(dāng)前進(jìn)度動(dòng)畫(huà)過(guò)渡到目標(biāo)值
實(shí)現(xiàn)放大動(dòng)畫(huà)
1.代碼
@Composable
fun animSize() {
val enable = remember {
mutableStateOf(true)
}
val size =
animateSizeAsState(targetValue = if (enable.value) Size(50f, 50f) else Size(300f, 300f))
Column(
modifier = Modifier.fillMaxSize(1f),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Image(
modifier = Modifier
.size(size.value.width.dp, size.value.height.dp)
.clickable {
enable.value = !enable.value
},
painter = painterResource(id = R.drawable.apple),
contentDescription = ""
)
}
}2.實(shí)現(xiàn)效果

實(shí)現(xiàn)顏色變化動(dòng)畫(huà)
1.代碼
@Composable
fun animColor() {
val enable = remember {
mutableStateOf(true)
}
val colors = animateColorAsState(targetValue = if (enable.value) Color.Green else Color.Red)
val size = animateIntSizeAsState(
targetValue = if (enable.value) IntSize(100, 100) else IntSize(
300,
300
)
)
Column(
modifier = Modifier.fillMaxWidth(1f),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Box(
modifier = Modifier
.size(size.value.width.dp, size.value.height.dp)
.height(400.dp)
.background(
color = colors.value,
shape = if (enable.value) RectangleShape else CircleShape
)
) {
}
}
}2.效果

使用 Animatable 實(shí)現(xiàn)顏色變化效果
Animatable 是一個(gè)值容器,我們可以通過(guò)調(diào)用 animateTo 實(shí)現(xiàn)動(dòng)畫(huà)效果。動(dòng)畫(huà)執(zhí)行過(guò)程中如果再次開(kāi)啟動(dòng)畫(huà)會(huì)中斷當(dāng)前動(dòng)畫(huà)。
Animatable 動(dòng)畫(huà)執(zhí)行過(guò)程中值的變化是在協(xié)程中執(zhí)行的,所以 animateTo 是一個(gè)掛起操作
1.代碼
@Composable
fun animChangeColor() {
val color = remember {
Animatable(Color.Red)
}
val state = remember {
mutableStateOf(true)
}
LaunchedEffect(state.value) {
color.animateTo(if (state.value) Color.Red else Color.Magenta)
}
Box(Modifier.fillMaxSize(1f), contentAlignment = Alignment.Center) {
Box(
modifier = Modifier
.background(color.value, shape = RoundedCornerShape(30.dp))
.size(200.dp)
.clickable {
state.value = !state.value
}, contentAlignment = Alignment.Center
) {
Text(
text = "顏色動(dòng)畫(huà)",
style = TextStyle(color = Color.White, fontSize = 40.sp)
)
}
}
}2.效果

使用 updateTransition 實(shí)現(xiàn)顏色和圓角動(dòng)畫(huà)
使用 updateTransition 可以實(shí)現(xiàn)多個(gè)動(dòng)畫(huà)組合的效果。
例如:我們可以在動(dòng)畫(huà)執(zhí)行過(guò)程中同時(shí)執(zhí)行大小和顏色變化效果
本例中我們定義了一個(gè)枚舉用來(lái)控制動(dòng)畫(huà),枚舉可以定義多個(gè),分別用來(lái)對(duì)應(yīng)動(dòng)畫(huà)的多個(gè)狀態(tài)
1.代碼
@Composable
fun animupdateTransition() {
var state by remember {
mutableStateOf(BoxState.Collapsed)
}
val transition = updateTransition(targetState = state, label = "")
val round = transition.animateDp(label = "") {
when (it) {
BoxState.Collapsed -> 40.dp
BoxState.Expanded -> 100.dp
}
}
val color = transition.animateColor(label = "") {
when (it) {
BoxState.Collapsed -> Color.Red
BoxState.Expanded -> Color.Green
}
}
Box(Modifier.fillMaxSize(1f),contentAlignment = Alignment.Center) {
Box(
modifier = Modifier
.size(300.dp)
.background(
color.value,
shape = RoundedCornerShape(corner = CornerSize(round.value))
)
.clickable {
state =
if (state == BoxState.Collapsed) BoxState.Expanded else BoxState.Collapsed
},contentAlignment = Alignment.Center
) {
Text(text = "點(diǎn)擊開(kāi)始動(dòng)畫(huà)",style = TextStyle(color = Color.White,fontSize = 20.sp))
}
}
}
private enum class BoxState {
Collapsed,
Expanded
}2.效果

rememberInfiniteTransition
rememberInfiniteTransition 的使用和 updateTransition 基本一樣,不同的是 rememberInfiniteTransition 的動(dòng)畫(huà)一旦開(kāi)始便會(huì)一直反復(fù)運(yùn)行下去,只有被移除動(dòng)畫(huà)才能結(jié)束
1.代碼
@Composable
fun rememberInfiniteTransition1() {
val infiniteTransition = rememberInfiniteTransition()
val color by infiniteTransition.animateColor(
initialValue = Color.Red,
targetValue = Color.Green,
animationSpec = infiniteRepeatable(
animation = tween(1000, easing = LinearEasing),
repeatMode = RepeatMode.Reverse
)
)
Box(Modifier.fillMaxSize(1f), contentAlignment = Alignment.Center) {
Box(
Modifier
.fillMaxSize(0.8f)
.background(color),
contentAlignment = Alignment.Center
) {
Text(
text = "公眾號(hào):安安安安卓 原創(chuàng),禁抄襲",
style = TextStyle(color = Color.White, fontSize = 30.sp)
)
}
}
}2.效果 ???????

TargetBasedAnimation
TargetBasedAnimation 可以控制動(dòng)畫(huà)的執(zhí)行時(shí)間,還可以延遲一段時(shí)間再開(kāi)啟動(dòng)畫(huà)。
1.代碼
@Composable
fun animTargetBasedAnimation() {
var state by remember {
mutableStateOf(0)
}
val anim = remember {
TargetBasedAnimation(
animationSpec = tween(2000),
typeConverter = Float.VectorConverter,
initialValue = 100f,
targetValue = 300f
)
}
var playTime by remember { mutableStateOf(0L) }
var animationValue by remember {
mutableStateOf(0)
}
LaunchedEffect(state) {
val startTime = withFrameNanos { it }
println("進(jìn)入?yún)f(xié)程:")
do {
playTime = withFrameNanos { it } - startTime
animationValue = anim.getValueFromNanos(playTime).toInt()
} while (!anim.isFinishedFromNanos(playTime))
}
Box(modifier = Modifier.fillMaxSize(1f),contentAlignment = Alignment.Center) {
Box(modifier = Modifier
.size(animationValue.dp)
.background(Color.Red,shape = RoundedCornerShape(animationValue/5))
.clickable {
state++
},contentAlignment = Alignment.Center) {
Text(text = animationValue.toString(),style = TextStyle(color = Color.White,fontSize = (animationValue/5).sp))
}
}
}2.效果 ???????

自定義動(dòng)畫(huà)
AnimationSpec
AnimationSpec 可以自定義動(dòng)畫(huà)的行為,效果類(lèi)似于原生動(dòng)畫(huà)中的估值器。
SpringSpec 彈簧效果
1.代碼
@Composable
fun animSpring() {
val state = remember {
mutableStateOf(true)
}
var value = animateIntAsState(
targetValue = if (state.value) 300 else 100,
animationSpec = spring(
dampingRatio = Spring.DampingRatioHighBouncy,
stiffness = Spring.StiffnessVeryLow
)
)
Box(
Modifier
.fillMaxSize(1f)
.padding(start = 30.dp), contentAlignment = Alignment.CenterStart
) {
Box(
Modifier
.width(value.value.dp)
.height(80.dp)
.background(Color.Red, RoundedCornerShape(topEnd = 30.dp, bottomEnd = 30.dp))
.clickable {
state.value = !state.value
}, contentAlignment = Alignment.CenterStart
) {
Text(text = "哈哈哈", style = TextStyle(color = Color.White, fontSize = 20.sp))
}
}
}2.效果 ???????

TweenSpec 動(dòng)畫(huà)時(shí)間可控
1.代碼
@Composable
fun animTweenSpec() {
val state = remember {
mutableStateOf(true)
}
val value = animateIntAsState(
targetValue = if (state.value) 300 else 100,
animationSpec = tween(
durationMillis = 1500,
delayMillis = 200,
easing = LinearEasing
)
)
Box(
Modifier
.fillMaxSize(1f)
.padding(start = 50.dp), contentAlignment = Alignment.CenterStart
) {
Box(
Modifier
.width(value.value.dp)
.height(100.dp)
.background(Color.Red, RoundedCornerShape(topEnd = 30.dp, bottomEnd = 30.dp))
.clickable {
state.value = !state.value
}
) {
}
}
}2.效果 ???????

FrameSpec
1.代碼
@Composable
fun animkeyframesSpec() {
var state by remember {
mutableStateOf(true)
}
val value by animateIntAsState(
targetValue = if (state) 300 else 100,
animationSpec = keyframes {
durationMillis = 2000
0 at 700 with LinearOutSlowInEasing
700 at 1400 with FastOutLinearInEasing
1400 at 2000
})
Box(Modifier.fillMaxSize(1f), contentAlignment = Alignment.CenterStart) {
Box(
Modifier
.width(value.dp)
.height(100.dp)
.background(Color.Red, RoundedCornerShape(topEnd = 30.dp, bottomEnd = 30.dp))
.clickable {
state = !state
}
) {
}
}
}2.效果

RepeatableSpec 實(shí)現(xiàn)有限次數(shù)的重復(fù)動(dòng)畫(huà)
執(zhí)行有限次數(shù)動(dòng)畫(huà)后自動(dòng)停止
1.代碼
@Composable
fun animrepeatableSpec() {
var state by remember {
mutableStateOf(true)
}
val value by animateIntAsState(
targetValue = if (state) 300 else 100,
animationSpec = repeatable(
iterations = 5,//動(dòng)畫(huà)重復(fù)執(zhí)行的次數(shù),設(shè)置多少就執(zhí)行多少次
animation = tween(durationMillis = 1000),
repeatMode = RepeatMode.Reverse
)
)
Box(
Modifier
.fillMaxSize(1f)
.padding(start = 30.dp), contentAlignment = Alignment.CenterStart) {
Box(
Modifier
.width(value.dp)
.height(100.dp)
.background(Color.Red, RoundedCornerShape(topEnd = 30.dp, bottomEnd = 30.dp))
.clickable {
state = !state
}
) {
}
}
}2.效果
代碼中設(shè)置了重復(fù) 5 次,所以反復(fù)執(zhí)行五次后動(dòng)畫(huà)結(jié)束

InfiniteRepeatableSpec 無(wú)限次數(shù)執(zhí)行動(dòng)畫(huà)
動(dòng)畫(huà)會(huì)無(wú)限次的執(zhí)行下去,直到視圖被移除
1.代碼
@Composable
fun animinfiniteRepeatableSpec() {
var state by remember {
mutableStateOf(true)
}
val value by animateIntAsState(
targetValue = if (state) 300 else 100,
animationSpec = infiniteRepeatable(
animation = tween(durationMillis = 1000),
repeatMode = RepeatMode.Reverse
)
)
Box(
Modifier
.fillMaxSize(1f)
.padding(start = 30.dp), contentAlignment = Alignment.CenterStart) {
Box(
Modifier
.width(value.dp)
.height(100.dp)
.background(Color.Red, RoundedCornerShape(topEnd = 30.dp, bottomEnd = 30.dp))
.clickable {
state = !state
}
) {
Text(text = "公眾號(hào):安安安安卓 原創(chuàng),禁轉(zhuǎn)載")
}
}
}2.效果

Easing
Easing 類(lèi)似于我們?cè)鷦?dòng)畫(huà)中的差值器
有以下幾種選擇:
- FastOutSlowInEasing
- LinearOutSlowInEasing
- FastOutLinearInEasing
- LinearEasing
- CubicBezierEasing
這幾種實(shí)現(xiàn)的效果和 android 原生實(shí)現(xiàn)的動(dòng)畫(huà)差值器差距很大,甚至看不出有啥效果,所以代碼我就不放了。有清楚原因的讀者可以聯(lián)系我
實(shí)現(xiàn)效果:

AnimationVector
大多數(shù) Compose 動(dòng)畫(huà) API 都支持將 Float、Color、Dp 以及其他基本數(shù)據(jù)類(lèi)型作為開(kāi)箱即用的動(dòng)畫(huà)值,但有時(shí)我們需要為其他數(shù)據(jù)類(lèi)型(包括我們的自定義類(lèi)型)添加動(dòng)畫(huà)效果
本例中實(shí)現(xiàn)顏色和大小的變換動(dòng)畫(huà)
代碼中我們定義了一個(gè) AnimSize 類(lèi),類(lèi)中的第一個(gè)參數(shù)是顏色數(shù)據(jù),第二個(gè)參數(shù)是尺寸數(shù)據(jù)。動(dòng)畫(huà)執(zhí)行過(guò)程中會(huì)同事改變顏色和控件尺寸效果。
1.代碼
@Composable
fun animAnimationVector() {
var state by remember {
mutableStateOf(true)
}
val value by animateValueAsState(
targetValue = if (state) AnimSize(0xffff5500, 100f) else AnimSize(0xff00ff00, 300f),
typeConverter = TwoWayConverter(
convertToVector = {
// AnimationVector2D(target.color.toFloat(), target.size)
AnimationVector2D(it.color.toFloat(), it.size)
},
convertFromVector = {
AnimSize(it.v1.toLong(), it.v2)
}
)
)
println("顏色:${value.color}")
Box(modifier = Modifier.fillMaxSize(1f).padding(30.dp), contentAlignment = Alignment.Center) {
Box(
modifier = Modifier
.size(value.size.dp)
// .size(300.dp)
.background(Color(value.color), RoundedCornerShape(30.dp))
.clickable {
state = !state
}
) {
}
}
}
data class AnimSize(val color: Long, val size: Float)2.效果
缺點(diǎn)是執(zhí)行顏色變化過(guò)程中有閃爍

高級(jí)動(dòng)畫(huà)
高級(jí)動(dòng)畫(huà)一般指封裝性較高的動(dòng)畫(huà),使用較為簡(jiǎn)單,主要有以下三種:
因高級(jí)動(dòng)畫(huà)效果不明顯,gif 很難展現(xiàn)出效果,所以這里不放代碼和效果圖了
- AnimatedVisibility
- animateContentSize
- Crossfade
以上就是Jetpack Compose實(shí)現(xiàn)動(dòng)畫(huà)效果的方法詳解的詳細(xì)內(nèi)容,更多關(guān)于Jetpack Compose動(dòng)畫(huà)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Android Compose 屬性動(dòng)畫(huà)使用探索詳解
- Compose開(kāi)發(fā)之動(dòng)畫(huà)藝術(shù)探索及實(shí)現(xiàn)示例
- Android中分析Jetpack?Compose動(dòng)畫(huà)內(nèi)部的實(shí)現(xiàn)原理
- Jetpack Compose實(shí)現(xiàn)列表和動(dòng)畫(huà)效果詳解
- 通過(guò)Jetpack Compose實(shí)現(xiàn)雙擊點(diǎn)贊動(dòng)畫(huà)效果
- 利用Jetpack Compose繪制可愛(ài)的天氣動(dòng)畫(huà)
- Android之Compose頁(yè)面切換動(dòng)畫(huà)介紹
- Compose?動(dòng)畫(huà)藝術(shù)之屬性動(dòng)畫(huà)探索
相關(guān)文章
Android實(shí)現(xiàn)在TextView文字過(guò)長(zhǎng)時(shí)省略部分或滾動(dòng)顯示的方法
這篇文章主要介紹了Android實(shí)現(xiàn)在TextView文字過(guò)長(zhǎng)時(shí)省略部分或滾動(dòng)顯示的方法,結(jié)合實(shí)例形式分析了Android中TextView控件文字顯示及滾動(dòng)效果相關(guān)操作技巧,需要的朋友可以參考下2016-10-10
android 捕獲系統(tǒng)異常并上傳日志具體實(shí)現(xiàn)
這篇文章介紹了android 捕獲系統(tǒng)異常并上傳日志具體實(shí)現(xiàn),有需要的朋友可以參考一下2013-09-09
Android Canvas之drawBitmap方法案例詳解
這篇文章主要介紹了Android Canvas之drawBitmap方法案例詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08
Android如何通過(guò)Retrofit提交Json格式數(shù)據(jù)
本篇文章主要介紹了Android如何通過(guò)Retrofit提交Json格式數(shù)據(jù),具有一定的參考價(jià)值,有興趣的可以了解一下2017-08-08
Android運(yùn)用onTouchEvent自定義滑動(dòng)布局
這篇文章主要為大家詳細(xì)介紹了Android運(yùn)用onTouchEvent寫(xiě)一個(gè)上下滑動(dòng)的布局,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03
Android程序開(kāi)發(fā)之防止密碼輸入錯(cuò)誤 密碼明文顯示功能
在使用App的時(shí)候,首次登錄都需要用戶(hù)輸入密碼的,有些朋友為了安全起見(jiàn)密碼設(shè)置的比較長(zhǎng),導(dǎo)致很多次密碼都輸入錯(cuò)誤,嚴(yán)重影響了用戶(hù)體驗(yàn)效果,下面通過(guò)本文給大家介紹Android程序開(kāi)發(fā)之防止密碼輸入錯(cuò)誤 密碼明文顯示功能,需要的朋友參考下2016-02-02
Android BottomSheet實(shí)現(xiàn)可拉伸控件
這篇文章主要為大家詳細(xì)介紹了Android BottomSheet實(shí)現(xiàn)可拉伸控件,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-11-11

