0Pricing
Android Academy · 课时

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 反馈 — 无需本地设置。

此课程中的所有课时

  1. 动画为何重要
  2. animate*AsState 基础
  3. AnimatedVisibility 与过渡
  4. 手势与弹簧动画
← 返回 Android Academy