Jetpack Compose 动画 (动画修饰符和可组合项)

内置动画可组合项

使用 AnimatedVisibility 为出现和消失添加动画效果

ts 复制代码
@Composable
private fun example1() {
  val visible = remember { mutableStateOf(false) }
  Column {
      customTitle(title = "内置动画可组合项")

      Button(modifier = Modifier.padding(start = 15.dp), onClick = { visible.value = !visible.value }) {
          Text(text = if (visible.value) "隐藏另一个按钮" else "显示另一个按钮")
      }
      AnimatedVisibility(visible.value) {
          Button(modifier = Modifier.padding(start = 15.dp), onClick = { }) {
              Text(text = "另一个按钮")
          }
      }
  }
}

默认情况下,内容以淡入和扩大的方式出现,以淡出和缩小的方式消失。您可以通过指定 [EnterTransition] 和 [ExitTransition] 来自定义这种过渡效果。

ts 复制代码
@Composable
private fun example2() {
    val visible = remember { mutableStateOf(false) }
    Column {
        customTitle(title = "指定 EnterTransition 和 ExitTransition 来自定义过渡效果")

        Button(modifier = Modifier.padding(start = 15.dp), onClick = { visible.value = !visible.value }) {
            Text(text = if (visible.value) "隐藏另一个按钮" else "显示另一个按钮")
        }
        AnimatedVisibility(visible = visible.value,
            enter = expandVertically(),
            exit = shrinkVertically()) {
            Button(modifier = Modifier.padding(start = 15.dp), onClick = { }) {
                Text(text = "另一个按钮")
            }
        }       
    }
}

如上面的示例所示,您可以使用 + 运算符组合多个 EnterTransitionExitTransition 对象,并且每个对象都接受可选参数以自定义其行为。如需了解详情,请参阅相关参考资料。

EnterTransition ExitTransition
fadeIn fadeOut
slideIn slideOut
slideInHorizontally slideOutHorizontally
slideInVertically slideOutVertically
scaleIn scaleOut
expandIn shrinkOut
expandHorizontally shrinkHorizontally
expandVertically shrinkVertically

AnimatedVisibility 还提供了接受 MutableTransitionState 的变体。这样,只要将 AnimatedVisibility 添加到组合树中,您就可以立即触发动画。该属性还有助于观察动画状态。

ts 复制代码
@Composable
private fun example3() {
    val state = remember { MutableTransitionState(false) }
    Column {
        Button(modifier = Modifier.padding(start = 15.dp), enabled = state.isIdle, onClick = { state.targetState = !state.currentState }) {
            Text(text = when {
                state.isIdle && state.currentState -> "隐藏另一个按钮"
                !state.isIdle && state.currentState -> "正在隐藏..."
                state.isIdle && !state.currentState -> "显示另一个按钮"
                else -> "正在显示..."
            })
        }
        AnimatedVisibility(visibleState  = state) {
            Button(modifier = Modifier.padding(start = 15.dp), onClick = { }) {
                Text(text = "另一个按钮")
            }
        }     
    }
}

为子项添加进入和退出动画效果

AnimatedVisibility 中的内容(直接或间接子项)可以使用 [animateEnterExit] 修饰符为每个子项指定不同的动画行为。其中每个子项的视觉效果均由 AnimatedVisibility 可组合项中指定的动画与子项自己的进入和退出动画构成。

ts 复制代码
@OptIn(ExperimentalAnimationApi::class)
@Composable
private fun example4() {
    val visible = remember { mutableStateOf(false) }
    Column {
        customTitle(title = "为子项添加进入和退出动画效果")
        Button(modifier = Modifier.padding(start = 15.dp), onClick = { visible.value = !visible.value }) {
            Text(text = if (visible.value) "隐藏" else "显示")
        }
        AnimatedVisibility(
            visible = visible.value,
            enter = fadeIn(),
            exit = fadeOut()
        ) {
            // Fade in/out the background and the foreground.
            Box(
                Modifier
                    .fillMaxSize()
                    .background(Color.DarkGray)) {
                Box(
                    Modifier
                        .align(Alignment.Center)
                        .animateEnterExit(
                            // Slide in/out the inner box.
                            enter = slideInVertically(),
                            exit = slideOutVertically()
                        )
                        .sizeIn(minWidth = 256.dp, minHeight = 64.dp)
                        .background(Color.Red)
                ) {
                    // Content of the notification...
                }
            }
        }
    }
}

添加自定义动画

如果您想在内置进入和退出动画之外添加自定义动画效果,请通过 AnimatedVisibility 的内容 lambda 内的 transition 属性访问底层 Transition 实例。添加到 Transition 实例的所有动画状态都将与 AnimatedVisibility 的进入和退出动画同时运行。AnimatedVisibility 会等到 Transition 中的所有动画都完成后再移除其内容。对于独立于 Transition(例如使用 animate*AsState)创建的退出动画,AnimatedVisibility 将无法解释这些动画,因此可能会在完成之前移除内容可组合项。

ts 复制代码
@OptIn(ExperimentalAnimationApi::class)
@Composable
private fun example5() {
    val visible = remember { mutableStateOf(false) }
    Column {
        customTitle(title = "添加自定义动画")
        Button(modifier = Modifier.padding(start = 15.dp), onClick = { visible.value = !visible.value }) {
            Text(text = if (visible.value) "隐藏" else "显示")
        }
        AnimatedVisibility(
            visible = visible.value,
            enter = fadeIn(),
            exit = fadeOut()
        ) { // this: AnimatedVisibilityScope
            // Use AnimatedVisibilityScope#transition to add a custom animation
            // to the AnimatedVisibility.
            val background = transition.animateColor(label = "color") { state ->
                if (state == EnterExitState.Visible) Color.Blue else Color.Red
            }
            Box(modifier = Modifier.size(200.dp).background(background.value))
        }    
    }
}

使用 AnimatedContent 根据目标状态添加动画效果

`AnimatedContent`\] 可组合项会在内容根据目标状态发生变化时,为内容添加动画效果。 ![petal_20240412_100400_20240412_100437.gif](https://file.jishuzhan.net/article/1779826929759686658/fb168c9c30d1a4c503d5e930193e481a.webp) ```kotlin @Composable private fun example6() { val count = remember { mutableStateOf(0) } Column { customTitle(title = "使用 AnimatedContent 根据目标状态添加动画效果") Button(modifier = Modifier.padding(start = 15.dp), onClick = { count.value++ }) { Text(text = "自增") } AnimatedContent(targetState = count.value, label = "AnimatedContent") { targetCount -> // Make sure to use `targetCount`, not `count`. Text(text = "计数: $targetCount", style = TextStyle(fontSize = 20.sp), modifier = Modifier.padding(all = 15.dp)) } CodeView(assetUrl = "animation/animationModifierComposable/code5.txt", modifier = Modifier.padding(top = 10.dp)) } } ``` `EnterTransition` 定义了目标内容应如何显示,`ExitTransition` 则定义了初始内容应如何消失。除了可用于 `AnimatedVisibility` 的所有 `EnterTransition` 和 `ExitTransition` 函数之外,`AnimatedContent` 还提供了 \[`slideIntoContainer`\] 和 \[`slideOutOfContainer`\]。这些是 `slideInHorizontally/Vertically` 和 `slideOutHorizontally/Vertically` 的便捷替代方案,它们可根据初始内容的大小和 `AnimatedContent` 内容的目标内容来计算滑动距离。 \[`SizeTransform`\] 定义了大小应如何在初始内容与目标内容之间添加动画效果。在创建动画时,您可以访问初始大小和目标大小。`SizeTransform` 还可控制在动画播放期间是否应将内容裁剪为组件大小。 ![petal_20240412_180550_20240415_151701.gif](https://file.jishuzhan.net/article/1779826929759686658/36e187228e151b28b5167b8c4e667719.webp) ```ts @OptIn(ExperimentalAnimationApi::class) @Composable private fun example7() { val expanded = remember { mutableStateOf(false) } Column { customTitle(title = "使用 AnimatedContent 根据目标状态添加动画效果") Surface( color = MaterialTheme.colorScheme.primary, onClick = { expanded.value = !expanded.value } ) { AnimatedContent( targetState = expanded.value, transitionSpec = { fadeIn(animationSpec = tween(300, 150)) with fadeOut(animationSpec = tween(300)) using SizeTransform { initialSize, targetSize -> if (targetState) { keyframes { // Expand horizontally first. IntSize(targetSize.width, initialSize.height) at 300 durationMillis = 600 } } else { keyframes { // Shrink vertically first. IntSize(initialSize.width, targetSize.height) at 300 durationMillis = 600 } } } }, label = "AnimatedContent" ) { targetExpanded -> if (targetExpanded) { Text(text = "SizeTransform 定义了大小应如何在初始内容与目标内容之间添加动画效果。在创建动画时,您可以访问初始大小和目标大小。SizeTransform 还可控制在动画播放期间是否应将内容裁剪为组件大小", modifier = Modifier.size(300.dp).padding(all = 5.dp)) } else { Icon(imageVector = Icons.Filled.Call, contentDescription = "icon", modifier = Modifier.size(50.dp).padding(all = 5.dp)) } } } } } ``` [上一篇 Jetpack Compose 列表](https://juejin.cn/post/7356177721998131210 "https://juejin.cn/post/7356177721998131210")

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