您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關Jetpack Compose怎么實現動畫效果,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
compose 為支持動畫提供了大量的 api,通過這些 api 我們可以輕松實現動畫效果
ps:這些 api 的原理與 Flutter 很接近,與原生的 api 相去甚遠
你可以提前看看用 compose 實現的一個放大縮小動畫,總的來說還是比較流暢:
所能處理屬性的種類:Float、Color、Dp、Size、Bounds、Offset、Rect、Int、IntOffset 和 IntSize
通過 animate*AsState 我們可以實現單一屬性的動畫效果,我們只需要提供目標值就可以自動從當前進度動畫過渡到目標值
實現放大動畫
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.實現效果
實現顏色變化動畫
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 是一個值容器,我們可以通過調用 animateTo 實現動畫效果。動畫執行過程中如果再次開啟動畫會中斷當前動畫。
Animatable 動畫執行過程中值的變化是在協程中執行的,所以 animateTo 是一個掛起操作
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 = "顏色動畫", style = TextStyle(color = Color.White, fontSize = 40.sp) ) } } }
2.效果
使用 updateTransition 可以實現多個動畫組合的效果。
例如:我們可以在動畫執行過程中同時執行大小和顏色變化效果
本例中我們定義了一個枚舉用來控制動畫,枚舉可以定義多個,分別用來對應動畫的多個狀態
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 = "點擊開始動畫",style = TextStyle(color = Color.White,fontSize = 20.sp)) } } } private enum class BoxState { Collapsed, Expanded }
2.效果
rememberInfiniteTransition 的使用和 updateTransition 基本一樣,不同的是 rememberInfiniteTransition 的動畫一旦開始便會一直反復運行下去,只有被移除動畫才能結束
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 = "公眾號:安安安安卓 原創,禁抄襲", style = TextStyle(color = Color.White, fontSize = 30.sp) ) } } }
2.效果
TargetBasedAnimation 可以控制動畫的執行時間,還可以延遲一段時間再開啟動畫。
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("進入協程:") 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.效果
AnimationSpec 可以自定義動畫的行為,效果類似于原生動畫中的估值器。
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 動畫時間可控
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 實現有限次數的重復動畫
執行有限次數動畫后自動停止
1.代碼
@Composable fun animrepeatableSpec() { var state by remember { mutableStateOf(true) } val value by animateIntAsState( targetValue = if (state) 300 else 100, animationSpec = repeatable( iterations = 5,//動畫重復執行的次數,設置多少就執行多少次 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.效果
代碼中設置了重復 5 次,所以反復執行五次后動畫結束
InfiniteRepeatableSpec 無限次數執行動畫
動畫會無限次的執行下去,直到視圖被移除
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 = "公眾號:安安安安卓 原創,禁轉載") } } }
2.效果
Easing 類似于我們原生動畫中的差值器
有以下幾種選擇:
FastOutSlowInEasing
LinearOutSlowInEasing
FastOutLinearInEasing
LinearEasing
CubicBezierEasing
這幾種實現的效果和 android 原生實現的動畫差值器差距很大,甚至看不出有啥效果,所以代碼我就不放了。有清楚原因的讀者可以聯系我
實現效果:
大多數 Compose 動畫 API 都支持將 Float、Color、Dp 以及其他基本數據類型作為開箱即用的動畫值,但有時我們需要為其他數據類型(包括我們的自定義類型)添加動畫效果
本例中實現顏色和大小的變換動畫
代碼中我們定義了一個 AnimSize 類,類中的第一個參數是顏色數據,第二個參數是尺寸數據。動畫執行過程中會同事改變顏色和控件尺寸效果。
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.效果
缺點是執行顏色變化過程中有閃爍
高級動畫一般指封裝性較高的動畫,使用較為簡單,主要有以下三種:
因高級動畫效果不明顯,gif 很難展現出效果,所以這里不放代碼和效果圖了
AnimatedVisibility
animateContentSize
Crossfade
關于“Jetpack Compose怎么實現動畫效果”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。