An Exploration of the Internal Mechanism of Crossfade Composable

skydovesJaewoong Eum (skydoves)||6 min read

An Exploration of the Internal Mechanism of Crossfade Composable

In Jetpack Compose, Crossfade provides a simple and declarative way to animate the transition between two different UI states. When the targetState passed to it changes, it smoothly fades out the old content while simultaneously fading in the new content. While its public API is minimal, a study of its internal source code reveals a sophisticated state machine that manages the lifecycle of both the incoming and outgoing composables, orchestrates their animations, and ensures a seamless visual transition.

The entire mechanism is built upon the foundational Transition API, which is the core engine for state-based animations in Compose.

The Entry Point: Crossfade(targetState, ...)

The most common Crossfade function that developers use is a simple wrapper. Its entire purpose is to create and manage a Transition object for you.

@Composable
public fun <T> Crossfade(
    targetState: T,
    // ... modifier, animationSpec
    content: @Composable (T) -> Unit,
) {
    // 1. Create a Transition that tracks changes to targetState.
    val transition = updateTransition(targetState, label)
    
    // 2. Delegate to the more powerful Transition.Crossfade extension.
    transition.Crossfade(modifier, animationSpec, content = content)
}
  1. updateTransition(targetState): This is the key. It creates a Transition object that is aware of the targetState. Whenever the targetState value changes across recompositions, this Transition object will animate from its currentState to the new targetState.
  2. Delegation: It then immediately calls an extension function on this Transition object, transition.Crossfade(...), which contains the actual implementation logic.

This article continues for subscribers

Subscribe to Dove Letter for full access to 40+ deep-dive articles about Android and Kotlin development.

Become a Sponsor