AnimatedVisibility and Transitions
Animate showing and hiding content.
AnimatedVisibility and Transitions is a free Android Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Android Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Animating Appearance
Showing and hiding content abruptly feels jarring. Compose's AnimatedVisibility animates a composable as it enters and exits the layout.
Wrap your content in it and control visibility with a boolean. When that boolean changes, Compose plays an enter or exit animation instead of an instant pop.
@Composable
fun Greeting(show: Boolean) {
AnimatedVisibility(visible = show) {
Text("Welcome aboard!")
}
}Enter and Exit Transitions
You can choose exactly how content enters and leaves with the enter and exit parameters. Common building blocks include fadeIn/fadeOut, slideIn/slideOut, and expandVertically/shrinkVertically.
Combine them with the + operator to run several at once.
@Composable
fun Toast(show: Boolean) {
AnimatedVisibility(
visible = show,
enter = fadeIn() + slideInVertically { it },
exit = fadeOut() + slideOutVertically { it }
) {
Text("Item added to cart")
}
}Tuning the Transition Spec
Each enter/exit transition accepts an animationSpec, so you can control duration and easing just like with animate*AsState.
Here the content fades in over 300ms and out faster, over 150ms, a common pattern that makes dismissals feel snappy.
AnimatedVisibility(
visible = show,
enter = fadeIn(animationSpec = tween(300)),
exit = fadeOut(animationSpec = tween(150))
) {
Card { Text("Details") }
}Expand and Shrink
For sections that reveal more content, expandVertically and shrinkVertically animate the height, pushing surrounding content smoothly out of the way.
This is perfect for collapsible panels, FAQ items, or "show more" sections.
@Composable
fun Details(expanded: Boolean) {
AnimatedVisibility(
visible = expanded,
enter = expandVertically() + fadeIn(),
exit = shrinkVertically() + fadeOut()
) {
Text("Extra details revealed when expanded.")
}
}updateTransition: One State, Many Values
When several properties should change together based on one state, updateTransition coordinates them. It creates a Transition object whose children all animate in sync.
Define the state, then use animateColor, animateDp, etc., for each property as a function of that state.
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))
}Per-Property Timing in a Transition
A big advantage of updateTransition is per-property timing. Each animate* child can supply its own transitionSpec, so color and size can move at different speeds while staying coordinated by the same state.
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: Swapping Content
When the content itself changes, not just its visibility, use AnimatedContent. It animates between the old and new content, cross-fading by default.
It's ideal for things like a counter, a step indicator, or switching between loading and loaded states.
@Composable
fun Counter(count: Int) {
AnimatedContent(
targetState = count,
label = "counter"
) { value ->
Text("$value", style = MaterialTheme.typography.headlineLarge)
}
}Custom AnimatedContent Transitions
Customize how AnimatedContent swaps with transitionSpec. A classic for a counter is sliding the new value up while the old slides away, paired with a fade.
The using keyword attaches a SizeTransform so the container also resizes smoothly.
AnimatedContent(
targetState = count,
transitionSpec = {
(slideInVertically { it } + fadeIn()) togetherWith
(slideOutVertically { -it } + fadeOut())
},
label = "counter"
) { value -> Text("$value") }Animating List Items
Inside a LazyColumn, items that are added, removed, or moved can animate into place with Modifier.animateItem() on each item's content.
This gives smooth reordering and insertion without any manual bookkeeping.
LazyColumn {
items(tasks, key = { it.id }) { task ->
Text(
task.title,
modifier = Modifier.animateItem()
)
}
}Crossfade for Whole Screens
Crossfade is a simple, focused helper that fades between two states, great for switching whole screens or major UI states.
Pass the current state and a content lambda; when the state changes, Crossfade fades the old out and the new in.
@Composable
fun ScreenHost(screen: Screen) {
Crossfade(targetState = screen, label = "screen") { current ->
when (current) {
Screen.Home -> HomeScreen()
Screen.Profile -> ProfileScreen()
}
}
}Coordinating Enter Children
Inside an AnimatedVisibility block you get an AnimatedVisibilityScope, which exposes Modifier.animateEnterExit(). This lets individual children animate with their own enter/exit on top of the parent's transition.
For example, a panel can slide in while its title fades in slightly later for a layered effect.
AnimatedVisibility(visible = show, enter = slideInVertically()) {
Column {
Text(
"Title",
modifier = Modifier.animateEnterExit(
enter = fadeIn(tween(delayMillis = 100))
)
)
Text("Body")
}
}Quick Check
You want to animate the swap from a number 3 to a number 4, fading and sliding the new value in. Which API is the best fit?
Recap: Visibility & Transitions
You can now animate content appearing, disappearing, and changing:
AnimatedVisibilityanimates enter/exit withfadeIn/Out,slideIn/Out,expand/shrink, combinable with+.updateTransitioncoordinates many values from one state, each with its own spec.AnimatedContentanimates swaps between different content;Crossfadeis the simple fade variant.Modifier.animateItem()animates list insertions and reordering.
Next: gestures and physics-based spring animations for natural, interactive motion.
Frequently asked questions
Is the “AnimatedVisibility and Transitions” lesson free?
Yes — the full text of “AnimatedVisibility and Transitions” is free to read here on the web, and the Android Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Android Academy course, upgrade to CoddyKit PRO.
What will I learn in “AnimatedVisibility and Transitions”?
Animate showing and hiding content. You practise Android Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Android Academy?
No prior experience is required. Android Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “AnimatedVisibility and Transitions” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Android Academy lesson?
Yes. Every Android Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Why Animations Matter
- animate*AsState Basics
- AnimatedVisibility and Transitions
- Gesture and Spring Animations