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")

相关推荐
ljt27249606613 天前
Compose笔记(六十一)--SelectionContainer
android·笔记·android jetpack
QING6183 天前
Jetpack Compose 中的 ViewModel 作用域管理 —— 新手指南
android·kotlin·android jetpack
惟恋惜4 天前
Jetpack Compose 的状态使用之“界面状态”
android·android jetpack
喜熊的Btm4 天前
探索 Kotlin 的不可变集合库
kotlin·android jetpack
惟恋惜4 天前
Jetpack Compose 界面元素状态(UI Element State)详解
android·ui·android jetpack
惟恋惜4 天前
Jetpack Compose 多页面架构实战:从 Splash 到底部导航,每个 Tab 拥有独立 ViewModel
android·ui·架构·android jetpack
alexhilton6 天前
Jetpack Compose 2025年12月版本新增功能
android·kotlin·android jetpack
モンキー・D・小菜鸡儿7 天前
Android Jetpack Compose 基础控件介绍
android·kotlin·android jetpack·compose
darryrzhong9 天前
FluxImageLoader : 基于Coil3封装的 Android 图片加载库,旨在提供简单、高效且功能丰富的图片加载解决方案
android·github·android jetpack
我命由我123459 天前
Android 开发问题:在无法直接获取或者通过传递获取 Context 的地方如何获取 Context
android·java·java-ee·android studio·android jetpack·android-studio·android runtime