Mobile Development 17 min read

Understanding Visibility Animations in Jetpack Compose: A Source‑Code Walkthrough

This article explores Jetpack Compose's visibility animation APIs by dissecting the AnimatedVisibility composable, its EnterTransition and ExitTransition parameters, the underlying Transition system, and related helper functions, while providing concrete Kotlin code examples and explanations of how each component works together to produce smooth UI effects.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Understanding Visibility Animations in Jetpack Compose: A Source‑Code Walkthrough

From Visibility Animation

The article begins by revisiting the simple visibility animation shown in the previous post and introduces a more detailed example using AnimatedVisibility with a mutable state variable.

val visible = remember { mutableStateOf(true) }
AnimatedVisibility(visible = visible.value) {
    Text(text = "天青色等烟雨,而我在等你,炊烟袅袅升起,隔江千万里")
}

EnterTransition

The EnterTransition sealed class defines how content appears. Its source shows an immutable data holder TransitionData and an overloaded plus operator that allows combining multiple animations such as fadeIn() and expandIn() .

@Immutable
sealed class EnterTransition {
    internal abstract val data: TransitionData
    @Stable
    operator fun plus(enter: EnterTransition): EnterTransition {
        return EnterTransitionImpl(
            TransitionData(
                fade = data.fade ?: enter.data.fade,
                slide = data.slide ?: enter.data.slide,
                changeSize = data.changeSize ?: enter.data.changeSize,
                scale = data.scale ?: enter.data.scale
            )
        )
    }
    companion object { val None: EnterTransition = EnterTransitionImpl(TransitionData()) }
}

The accompanying data classes ( Fade , Slide , ChangeSize , Scale ) each hold the parameters needed for the respective animation, all of which share an animationSpec of type FiniteAnimationSpec .

ExitTransition

The ExitTransition mirrors EnterTransition with a similar sealed‑class structure and a plus operator for combining exit animations such as shrinkOut() and fadeOut() .

@Immutable
sealed class ExitTransition {
    internal abstract val data: TransitionData
    @Stable
    operator fun plus(exit: ExitTransition): ExitTransition {
        return ExitTransitionImpl(
            TransitionData(
                fade = data.fade ?: exit.data.fade,
                slide = data.slide ?: exit.data.slide,
                changeSize = data.changeSize ?: exit.data.changeSize,
                scale = data.scale ?: exit.data.scale
            )
        )
    }
    companion object { val None: ExitTransition = ExitTransitionImpl(TransitionData()) }
}

Transition System

The core of the animation logic is the Transition class, which tracks a mutable state and drives child animations. The helper updateTransition creates a Transition from a target boolean and a label.

@Composable
fun
updateTransition(targetState: T, label: String? = null): Transition
{
    val transition = remember { Transition(targetState, label = label) }
    transition.animateTo(targetState)
    DisposableEffect(transition) {
        onDispose { transition.onTransitionEnd() }
    }
    return transition
}

Child transitions are generated via createChildTransition and createChildTransitionInternal , which propagate the parent state to a new Transition instance and manage lifecycle cleanup.

AnimatedEnterExitImpl

The composable AnimatedEnterExitImpl ties everything together. It decides whether the content should be visible, creates a child transition, observes its state with LaunchedEffect and snapshotFlow , and finally composes the content inside a custom Layout that applies the appropriate modifiers.

@Composable
private fun
AnimatedEnterExitImpl(
    transition: Transition
, visible: (T) -> Boolean,
    modifier: Modifier, enter: EnterTransition,
    exit: ExitTransition, content: @Composable AnimatedVisibilityScope.() -> Unit
) {
    val isAnimationVisible = remember(transition) { mutableStateOf(visible(transition.currentState)) }
    if (visible(transition.targetState) || isAnimationVisible.value || transition.isSeeking) {
        val childTransition = transition.createChildTransition(label = "EnterExitTransition") { transition.targetEnterExit(visible, it) }
        LaunchedEffect(childTransition) {
            snapshotFlow { childTransition.currentState == EnterExitState.Visible || childTransition.targetState == EnterExitState.Visible }
                .collect { isAnimationVisible.value = it }
        }
        AnimatedEnterExitImpl(childTransition, modifier, enter = enter, exit = exit, content = content)
    }
}

The second overload of AnimatedEnterExitImpl receives a Transition<EnterExitState> and, when the state is visible, builds an AnimatedVisibilityScopeImpl and a Layout that applies the combined enter and exit modifiers.

Other Visibility Animations

Additional convenience overloads are provided for RowScope and ColumnScope>, each supplying sensible default enter/exit animations (horizontal for rows, vertical for columns). There are also variants that accept a MutableTransitionState<Boolean> for more explicit state handling.

@Composable
fun RowScope.AnimatedVisibility(
    visible: Boolean,
    modifier: Modifier = Modifier,
    enter: EnterTransition = fadeIn() + expandHorizontally(),
    exit: ExitTransition = fadeOut() + shrinkHorizontally(),
    label: String = "AnimatedVisibility",
    content: @Composable AnimatedVisibilityScope.() -> Unit
) { /* implementation similar to the generic version */ }

Conclusion

The article demonstrates how Jetpack Compose implements visibility animations by layering immutable data classes, sealed transition types, and a flexible Transition system, allowing developers to compose complex enter/exit effects with concise Kotlin code while keeping the runtime efficient and declarative.

animationAndroidKotlinJetpack ComposeCompose UIVisibility Animation
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.