内置动画可组合项
使用 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 = "另一个按钮")
}
}
}
}
如上面的示例所示,您可以使用 +
运算符组合多个 EnterTransition
或 ExitTransition
对象,并且每个对象都接受可选参数以自定义其行为。如需了解详情,请参阅相关参考资料。
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` 的所有 `EnterTransition` 和 `ExitTransition` 函数之外,`AnimatedContent` 还提供了 \[`slideIntoContainer`\] 和 \[`slideOutOfContainer`\]。这些是 `slideInHorizontally/Vertically` 和 `slideOutHorizontally/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 列表](https://juejin.cn/post/7356177721998131210 "https://juejin.cn/post/7356177721998131210")