← All release notes
Jetpack ComposeCompose 2024Dec 18, 2024 · 5 min read

Jetpack Compose: The 2024 Releases

Compose 1.7 ships shared element transitions and new lazy list animations, and strong skipping mode becomes the default.

2024 is the year Compose stopped feeling like it was catching up to the View system on specific gaps. Shared element transitions landed. Lazy lists got item animations, and the default recomposition strategy grew smarter about what it can skip without you annotating anything by hand.

The compiler was being rewritten on K2 through all of it, shipping alongside Kotlin 2.0.

#Shared element transitions arrive

A grid thumbnail and a detail screen's hero image are two composables sitting in different parts of the UI. They are not the same element. SharedTransitionLayout and the associated Modifier.sharedElement() API let them animate as if they were, matched by a shared key across the navigation transition.

@Composable
fun SharedImage(
    key: String,
    sharedTransitionScope: SharedTransitionScope,
    animatedVisibilityScope: AnimatedVisibilityScope,
    modifier: Modifier = Modifier
) {
    with(sharedTransitionScope) {
        Image(
            painter = painterResource(R.drawable.thumbnail),
            contentDescription = null,
            modifier = modifier.sharedElement(
                rememberSharedContentState(key = key),
                animatedVisibilityScope = animatedVisibilityScope
            )
        )
    }
}

Use it when a list-to-detail flow currently cuts between screens, since what it replaces is the hand-rolled crossfade-and-hope and what you get instead is an actual shared-element animation.

#Strong skipping mode becomes the default

Recomposition skips a composable when its inputs are stable and unchanged. The trouble was what counted as stable: lambdas capturing vars, some collection types, and plenty of other everyday things were historically treated as unstable, and every one of them forced a recomposition you did not need.

Strong skipping mode changes the compiler's stability inference so more of those cases skip safely, without you marking every parameter @Stable by hand.

It shipped as an opt-in Compose compiler flag first. On a current Compose compiler version, you likely have it already and did nothing to get it.

#Lazy list item animations

Modifier.animateItem() replaces the older animateItemPlacement() on LazyColumn/LazyRow items. It adds fade-in and fade-out on top of the placement animation, so items being added, removed, or reordered all animate.

LazyColumn {
    items(tasks, key = { it.id }) { task ->
        TaskRow(
            task = task,
            modifier = Modifier.animateItem()
        )
    }
}

A todo list is the obvious case. So is a reorderable settings screen, or anything else where a user action or a data change adds, removes, or shuffles the contents underneath. One requirement: each item needs a stable key, because that is how identity gets tracked across recompositions.

#Autofill support lands (experimental)

Compose gets its own autofill integration. Text fields can now participate in the platform's autofill framework, password managers and saved addresses included, the way EditText always could. The API is experimental in this window, so pilot it on a non-critical form and let the app-wide rollout wait.

#Compose Multiplatform for iOS reaches Beta

Outside the Jetpack namespace proper, JetBrains' Compose Multiplatform moved its iOS target to Beta in 2024. One Compose UI, targeting Android, iOS, desktop, and web.

Android-only teams evaluating multiplatform strategy should care about the date, because Beta is the point where "share the UI layer with iOS" stopped being a research project and became something a team could pilot with a realistic stability expectation. Real gaps versus a fully native iOS UI are still there.

#What to adopt first

Strong skipping mode is close to free. Verify it's enabled on your current Compose compiler and move on, because it's a compiler-level win rather than a code change.

Modifier.animateItem() is a drop-in upgrade anywhere animateItemPlacement() already appears, so do that migration opportunistically as you touch list code.

Shared element transitions deserve more care. Take your highest-traffic list-to-detail flow and adopt there first rather than as a blanket rollout; the API surface is new enough that you'll want to learn its edge cases on one screen before spreading it everywhere.

Autofill and Compose Multiplatform for iOS are both still experimental or Beta in this window. Track them. Don't build critical-path features on either one yet unless you're explicitly piloting.