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` 可组合项会在内容根据目标状态发生变化时,为内容添加动画效果。

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 的所有 EnterTransitionExitTransition 函数之外,AnimatedContent 还提供了 `slideIntoContainer``slideOutOfContainer`。这些是 slideInHorizontally/VerticallyslideOutHorizontally/Vertically 的便捷替代方案,它们可根据初始内容的大小和 AnimatedContent 内容的目标内容来计算滑动距离。

`SizeTransform` 定义了大小应如何在初始内容与目标内容之间添加动画效果。在创建动画时,您可以访问初始大小和目标大小。SizeTransform 还可控制在动画播放期间是否应将内容裁剪为组件大小。

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 列表

相关推荐
alexhilton4 天前
使用Android Archive进行打包
android·kotlin·android jetpack
Junerver7 天前
我写了一个 Compose Multiplatform 组件库,你可能会用到
kotlin·android jetpack
我命由我123458 天前
Jetpack Room - Room 查询返回列表无需判空、LIKE 关键字
android·java·开发语言·java-ee·android jetpack·android-studio·android runtime
QING6189 天前
Kotlin 日常开发常用语法糖整理 —— 速记
android·kotlin·android jetpack
我命由我123459 天前
Android 开发问题:EditText 控件的 android:imeOptions=“actionDone“ 属性不生效
android·java·java-ee·android studio·android jetpack·android-studio·android runtime
我命由我123459 天前
Android 开发问题:获取到的 Android ID 发生了变化
android·java·开发语言·java-ee·android studio·android jetpack·android runtime
我命由我123459 天前
Android 开发问题:Unable to find explicit activity class
android·java·java-ee·android studio·android jetpack·android-studio·android runtime
我命由我123459 天前
Android 开发问题:全局的主题颜色设置,导致 CheckBox 控件在勾选状态下不显示样式
android·java·开发语言·java-ee·intellij-idea·intellij idea·android jetpack
alexhilton11 天前
Android的Agent优先时代:构建时vs运行时
android·kotlin·android jetpack
我命由我1234512 天前
Android 开发问题:View 的 getWidth、getHeight 方法返回的值都为 0
android·java·java-ee·android studio·android jetpack·android-studio·android runtime