Jetpack Compose 动画(基于 value 的动画)

使用 animate*AsState 为单个值添加动画效果

`animate*AsState`\] 函数是 Compose 中最简单的动画 API,用于为单个值添加动画效果。您只需提供目标值(或结束值),该 API 就会从当前值开始向指定值播放动画。 下面举例说明了如何使用此 API 为 alpha 添加动画效果。只需将目标值封装在 \[`animateFloatAsState`\] 中,alpha 值就会是所提供值(在本例中为 `1f` 或 `0.5f`)之间的动画值。 ![petal_20240415_183321_20240415_183449.gif](https://file.jishuzhan.net/article/1780191029039730689/51b5d4177342399a0642a5f0c47b4499.webp) ```ts @Composable private fun example1() { val enabled = remember { mutableStateOf(true) } val alpha = animateFloatAsState(if (enabled.value) 1f else 0.5f, label = "animateFloatAsState", animationSpec = tween(durationMillis = 800) ) Column { customTitle(title = "使用 animate*AsState 为单个值添加动画效果") Button(modifier = Modifier.padding(start = 15.dp), onClick = { enabled.value = !enabled.value }) { Text(text = if (enabled.value) "半透明" else "非透明") } Box( Modifier.fillMaxWidth() .height(200.dp) .graphicsLayer(alpha = alpha.value) .background(Color.Red) ) } } ``` ## 使用 Transition 同时为多个属性添加动画效果 ### 将过渡效果与 `AnimatedVisibility` 和 `AnimatedContent` 搭配使用 ![petal_20240415_183740_20240415_184020.gif](https://file.jishuzhan.net/article/1780191029039730689/2e768e660d774b37173d54810e9067bc.webp) ```ts @OptIn(ExperimentalAnimationApi::class) @Composable private fun example2() { val selected = remember { mutableStateOf(false) } // Animates changes when `selected` is changed. val transition = updateTransition(selected.value, label = "selected state") val borderColor = transition.animateColor(label = "border color") { isSelected -> if (isSelected) Color.Magenta else Color.White } val elevation = transition.animateDp(label = "elevation") { isSelected -> if (isSelected) 10.dp else 2.dp } Column { customTitle(title = "使用 animate*AsState 为单个值添加动画效果") Surface( shape = RoundedCornerShape(8.dp), border = BorderStroke(2.dp, borderColor.value), shadowElevation = elevation.value, modifier = Modifier.padding(all=5.dp).clickable { selected.value = !selected.value } ) { Column(modifier = Modifier.fillMaxWidth().padding(16.dp)) { Text(text = "Hello, world!") // AnimatedVisibility 过渡 transition.AnimatedVisibility( visible = { targetSelected -> targetSelected }, enter = expandVertically(), exit = shrinkVertically() ) { Text(text = "It is fine today.") } // AnimatedContent 过渡 transition.AnimatedContent { targetState -> if (targetState) { Text(text = "Selected") } else { Icon(imageVector = Icons.Default.Phone, contentDescription = "Phone") } } } } CodeView(assetUrl = "animation/animationValue/code1.txt", modifier = Modifier.padding(top = 10.dp)) } } ``` ### 封装 Transition 并使其可重复使用 ![petal_20240416_112715_20240416_112742.gif](https://file.jishuzhan.net/article/1780191029039730689/377aa8dfc9b281a61b0c8957c1fdd30b.webp) ```ts @Composable private fun example3() { val boxState = remember { mutableStateOf(BoxState.Collapsed) } val transitionData = updateTransitionData(boxState.value) Column { customTitle(title = "使用 animate*AsState 为单个值添加动画效果") Box( modifier = Modifier .background(transitionData.color.value) .size(transitionData.size.value).clickable { if (boxState.value == BoxState.Collapsed) { boxState.value = BoxState.Expanded } else { boxState.value = BoxState.Collapsed } } ) } } enum class BoxState { Collapsed, Expanded } // 保存动画的值 the animation values. private data class TransitionData( val color: State, val size: State ) // Create a Transition and return its animation values. @Composable private fun updateTransitionData(boxState: BoxState): TransitionData { val transition = updateTransition(boxState, label = "box state") val color = transition.animateColor(label = "color", transitionSpec = { tween(durationMillis = 1000) }) { state -> when (state) { BoxState.Collapsed -> Color.Gray BoxState.Expanded -> Color.Red } } val size = transition.animateDp(label = "size", transitionSpec = { tween(durationMillis = 1000) }) { state -> when (state) { BoxState.Collapsed -> 64.dp BoxState.Expanded -> 128.dp } } return remember(transition) { TransitionData(color, size) } } ``` ## 使用 `rememberInfiniteTransition` 创建无限重复的动画 \[`InfiniteTransition`\] 可容纳一个或多个子动画(如 `Transition`),但这些动画一进入组合就会立即开始运行,并且不会停止,除非这些动画被移除。您可以使用 `rememberInfiniteTransition` 创建 `InfiniteTransition` 实例。您可以使用 `animateColor`、`animatedFloat` 或 `animatedValue` 添加子动画。您还需要指定 \[infiniteRepeatable\] 以指定动画规范。 ![petal_20240416_140138_20240416_140155.gif](https://file.jishuzhan.net/article/1780191029039730689/0a5bf0efc16e3c22335a4aaf81adccf3.webp) ```ts @Composable private fun example4() { val infiniteTransition = rememberInfiniteTransition(label = "") val color = infiniteTransition.animateColor( initialValue = Color.Red, targetValue = Color.Green, animationSpec = infiniteRepeatable( animation = tween(1000, easing = LinearEasing), repeatMode = RepeatMode.Reverse ), label = "" ) Column { customTitle(title = "使用 rememberInfiniteTransition 创建无限重复的动画") Box(modifier = Modifier.size(200.dp).background(color.value)) } } ``` ## 低级别动画 API ### `Animatable`:基于协程的单值动画 \[`Animatable`\] 是一个值容器,可以在通过 `animateTo` 更改值时为值添加动画效果。这是支持 `animate*AsState` 实现的 API。它可确保一致的连续性和互斥性,这意味着值变化始终是连续的,并且会取消任何正在播放的动画。 `Animatable` 的许多功能(包括 `animateTo`)以挂起函数的形式提供。这意味着,它们需要封装在适当的协程作用域内。例如,您可以使用 `LaunchedEffect` 可组合项针对指定键值的时长创建一个作用域。 ![petal_20240416_141823_20240416_142022.gif](https://file.jishuzhan.net/article/1780191029039730689/9a20acd14530fce83e53905ed5402a6d.webp) ```ts @Composable private fun example5() { val ok = remember { mutableStateOf(false) } // Start out gray and animate to green/red based on `ok` val color = remember { Animatable(Color.Gray) } Column { customTitle(title = "Animatable:基于协程的单值动画") Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.clickable { ok.value = !ok.value }) { Checkbox(checked = ok.value, onCheckedChange = { ok.value = it }) Text(text = "切换动画") } LaunchedEffect(ok.value) { color.animateTo(if (ok.value) Color.Green else Color.Red, animationSpec = tween(durationMillis = 1000)) } Box( Modifier .size(200.dp) .background(color.value)) } } ``` ### `Animation`:手动控制的动画 \[`Animation`\] 是可用的最低级别的 Animation API。到目前为止,我们看到的许多动画都是基于 Animation 构建的。`Animation` 子类型有两种:\[`TargetBasedAnimation`\] 和 \[`DecayAnimation`\]。 `Animation` 只能用于手动控制动画的时间。`Animation` 是无状态的,它没有任何生命周期概念。它充当更高级别 API 使用的动画计算引擎。 ![petal_20240416_144644_20240416_144930.gif](https://file.jishuzhan.net/article/1780191029039730689/665c9b634856aeb7c2e25d365d3f0c53.webp) ```ts @Composable private fun example6() { val state = remember { mutableStateOf(0) } val anim = remember { TargetBasedAnimation( animationSpec = tween(2000), typeConverter = Float.VectorConverter, initialValue = 100f, targetValue = 300f ) } val playTime = remember { mutableStateOf(0L) } val animationValue = remember { mutableStateOf(0) } Column { customTitle(title = "Animation:手动控制的动画") LaunchedEffect(state.value) { val startTime = withFrameNanos { it } do { playTime.value = withFrameNanos { it } - startTime animationValue.value = anim.getValueFromNanos(playTime.value).toInt() } while (!anim.isFinishedFromNanos(playTime.value)) } Box(modifier = Modifier .size(animationValue.value.dp) .background(Color.Red,shape = RoundedCornerShape(animationValue.value / 5)) .clickable { state.value++ },contentAlignment = Alignment.Center) { Text(text = animationValue.value.toString(), style = TextStyle(color = Color.White,fontSize = (animationValue.value / 5).sp)) } } } ``` [上一篇 Jetpack Compose 动画(动画修饰符和可组合项)](https://juejin.cn/post/7357716989781934107 "https://juejin.cn/post/7357716989781934107")

相关推荐
peakmain96 小时前
Jetpack Compose UI组件封装(一)
android jetpack
alexhilton2 天前
实战:探索Jetpack Compose中的SearchBar
android·kotlin·android jetpack
顾林海3 天前
Jetpack Pager 使用与原理解析
android·android jetpack
每次的天空4 天前
Android Jetpack学习总结(源码级理解)
android·学习·android jetpack
顾林海5 天前
Jetpack Room 使用与原理解析
android·android jetpack
ljt27249606617 天前
Compose笔记(十三)--事件总线
笔记·android jetpack
我命由我123457 天前
Android Gradle 插件问题:The option ‘android.useDeprecatedNdk‘ is deprecated.
android·java·java-ee·android studio·android jetpack·android-studio·android runtime
Mr_万能胶8 天前
要失业了!写在 Android “不再开源”之后
android·android studio·android jetpack
QING6189 天前
Android Jetpack Paging 使用指南
kotlin·app·android jetpack
顾林海9 天前
Jetpack DataBinding 使用与原理解析
android·android jetpack