AnimatedVisibility 与过渡
为内容的显示和隐藏添加动画
AnimatedVisibility 与过渡 是 CoddyKit 上的免费 Android Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Android Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Android Academy 课程共包含 4 节课。
为出现效果添加动画
突然显示和隐藏内容会让人感到突兀。Compose 的 AnimatedVisibility 会为可组合项进入和离开布局添加动画。
将内容包裹在其中,并使用布尔值控制可见性。当布尔值发生变化时,Compose 会播放进入或退出动画,而不是让内容瞬间出现或消失。
@Composable
fun Greeting(show: Boolean) {
AnimatedVisibility(visible = show) {
Text("Welcome aboard!")
}
}进入与退出过渡
您可以通过 enter 和 exit 参数精确选择内容进入和离开的方式。常见的构建模块包括 fadeIn/fadeOut、slideIn/slideOut,以及 expandVertically/shrinkVertically。
使用 + 运算符可以将它们组合起来并同时运行。
@Composable
fun Toast(show: Boolean) {
AnimatedVisibility(
visible = show,
enter = fadeIn() + slideInVertically { it },
exit = fadeOut() + slideOutVertically { it }
) {
Text("Item added to cart")
}
}调整过渡规格
每个进入/退出过渡都接受 animationSpec,因此您可以像使用 animate*AsState 一样控制时长和缓动。
在这里,内容会在 300 毫秒内淡入,并以更快的速度在 150 毫秒内淡出。这是一种常见模式,可以让关闭操作显得干脆利落。
AnimatedVisibility(
visible = show,
enter = fadeIn(animationSpec = tween(300)),
exit = fadeOut(animationSpec = tween(150))
) {
Card { Text("Details") }
}展开与收缩
对于需要展示更多内容的区域,expandVertically 和 shrinkVertically 会为高度添加动画,让周围内容平滑地移开。
这非常适合可折叠面板、FAQ 条目或“显示更多”区域。
@Composable
fun Details(expanded: Boolean) {
AnimatedVisibility(
visible = expanded,
enter = expandVertically() + fadeIn(),
exit = shrinkVertically() + fadeOut()
) {
Text("Extra details revealed when expanded.")
}
}updateTransition:一个状态,多个值
当多个属性需要根据同一个状态一起变化时,updateTransition 会协调它们。它会创建一个 Transition 对象,其子项都会同步进行动画。
先定义状态,然后使用 animateColor、animateDp 等函数,让每个属性根据该状态变化。
enum class BoxState { Collapsed, Expanded }
@Composable
fun MorphingBox(state: BoxState) {
val transition = updateTransition(state, label = "box")
val size by transition.animateDp(label = "size") {
if (it == BoxState.Expanded) 200.dp else 100.dp
}
val color by transition.animateColor(label = "color") {
if (it == BoxState.Expanded) Color.Magenta else Color.Cyan
}
Box(Modifier.size(size).background(color))
}过渡中的属性独立计时
updateTransition 的一大优势是可以为每个属性单独设置时间。每个 animate* 子项都可以提供自己的 transitionSpec,因此颜色和大小可以以不同速度变化,同时仍由同一个状态协调。
val size by transition.animateDp(
transitionSpec = { tween(durationMillis = 300) },
label = "size"
) { if (it == BoxState.Expanded) 200.dp else 100.dp }
val corner by transition.animateDp(
transitionSpec = { tween(durationMillis = 600) },
label = "corner"
) { if (it == BoxState.Expanded) 0.dp else 24.dp }AnimatedContent:切换内容
当发生变化的是内容本身,而不仅仅是可见性时,请使用 AnimatedContent。它会在旧内容和新内容之间添加动画,默认采用交叉淡化。
它非常适合计数器、步骤指示器,或在加载中与加载完成状态之间切换等场景。
@Composable
fun Counter(count: Int) {
AnimatedContent(
targetState = count,
label = "counter"
) { value ->
Text("$value", style = MaterialTheme.typography.headlineLarge)
}
}自定义 AnimatedContent 过渡
使用 transitionSpec 自定义 AnimatedContent 的切换方式。计数器常用的一种效果是让新值向上滑入、旧值滑出,同时配合淡化。
using 关键字会附加一个 SizeTransform,使容器也能平滑地调整大小。
AnimatedContent(
targetState = count,
transitionSpec = {
(slideInVertically { it } + fadeIn()) togetherWith
(slideOutVertically { -it } + fadeOut())
},
label = "counter"
) { value -> Text("$value") }为列表项添加动画
在 LazyColumn 中,通过在每个列表项的内容上使用 Modifier.animateItem(),可以为添加、删除或移动的列表项添加就位动画。
这样无需手动记录状态,就能实现平滑的重新排序和插入效果。
LazyColumn {
items(tasks, key = { it.id }) { task ->
Text(
task.title,
modifier = Modifier.animateItem()
)
}
}为整个屏幕使用交叉淡化
Crossfade 是一个简单而专注的辅助函数,可在两种状态之间进行淡化切换,非常适合切换整个屏幕或主要界面状态。
传入当前状态和内容 lambda;当状态发生变化时,Crossfade 会让旧内容淡出、新内容淡入。
@Composable
fun ScreenHost(screen: Screen) {
Crossfade(targetState = screen, label = "screen") { current ->
when (current) {
Screen.Home -> HomeScreen()
Screen.Profile -> ProfileScreen()
}
}
}协调进入动画中的子项
在 AnimatedVisibility 代码块中,您可以获得一个 AnimatedVisibilityScope,它提供了 Modifier.animateEnterExit()。这样,单个子项就能在父项过渡的基础上,使用自己的进入/退出动画。
例如,面板可以滑入,而标题稍晚一些淡入,从而形成分层效果。
AnimatedVisibility(visible = show, enter = slideInVertically()) {
Column {
Text(
"Title",
modifier = Modifier.animateEnterExit(
enter = fadeIn(tween(delayMillis = 100))
)
)
Text("Body")
}
}快速检查
您希望为数字 3 切换到数字 4 的过程添加动画,让新值淡入并滑入。哪种 API 最适合?
回顾:可见性与过渡
现在您已经可以为内容的出现、消失和变化添加动画:
AnimatedVisibility使用fadeIn/Out、slideIn/Out、expand/shrink添加进入/退出动画,并可通过+进行组合。updateTransition根据一个状态协调多个值,每个值都可以使用自己的规格。AnimatedContent为不同内容之间的切换添加动画;Crossfade是简单的淡化变体。Modifier.animateItem()为列表项插入和重新排序添加动画。
接下来:学习手势和基于物理效果的弹簧动画,打造自然、可交互的运动效果。
常见问题解答
「AnimatedVisibility 与过渡」课时是免费的吗?
是的 — 「AnimatedVisibility 与过渡」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Android Academy 课程的其余内容,请升级到 CoddyKit PRO。 Android Academy 课程共包含 4 节课。
「AnimatedVisibility 与过渡」这节课中我会学到什么?
为内容的显示和隐藏添加动画 你通过在浏览器中直接运行的动手代码来练习 Android Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Android Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Android Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。
「AnimatedVisibility 与过渡」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Android Academy 课中编写并运行代码吗?
能。每节 Android Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 动画为何重要
- animate*AsState 基础
- AnimatedVisibility 与过渡
- 手势与弹簧动画