2024 is the year Compose stopped feeling like it was catching up to the View system on specific gaps. Shared element transitions. List-item animations. A smarter default recomposition strategy. All of it landed while the compiler picked up the K2-driven rewrite that shipped 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. SharedTransitionLayout and the associated Modifier.sharedElement() API let them animate as if they were the same element during a navigation transition, matched by a shared key.
@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 navigation flow currently just cuts between screens. This is the API that replaces the hand-rolled crossfade-and-hope with an actual shared-element animation.
#Strong skipping mode becomes the default
Compose's recomposition skips a composable when its inputs are stable and unchanged. The trouble was what counted as stable — lambdas capturing vars, some collection types, plenty of everyday things were historically treated as unstable and forced unnecessary recomposition.
Strong skipping mode changes the compiler's stability inference to skip more of these cases safely, without requiring you to mark every parameter @Stable by hand. It shipped as an opt-in Compose compiler flag before becoming the default. If you're on a current Compose compiler version you likely have it without doing anything.
#Lazy list item animations
Modifier.animateItem() replaces the older animateItemPlacement() on LazyColumn/LazyRow items, adding fade-in and fade-out animations alongside placement animation when items are added, removed, or reordered.
LazyColumn {
items(tasks, key = { it.id }) { task ->
TaskRow(
task = task,
modifier = Modifier.animateItem()
)
}
}
Use it when items get added, removed, or reordered in response to user action or data changes — a todo list, a queue, a reorderable settings screen. Each item needs a stable key to track identity 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, saved addresses — the way EditText always could. It ships as an experimental API in this window, so pilot it on a non-critical form rather than rolling it across your whole app immediately.
#Compose Multiplatform for iOS reaches Beta
Outside the Jetpack namespace proper, JetBrains' Compose Multiplatform — a single Compose UI targeting Android, iOS, desktop, and web — moved its iOS target to Beta in 2024. This matters even for Android-only teams evaluating multiplatform strategy. It's the point where "share the UI layer with iOS" stopped being a research project and started being something teams could pilot with a realistic stability expectation. Beta still means real gaps versus a fully native iOS UI.
#What to adopt first
- Strong skipping mode is close to free — if you're on a current Compose compiler, verify it's enabled and move on; it's a compiler-level win, not a code change.
Modifier.animateItem()is a drop-in upgrade anywhere you already useanimateItemPlacement(). Do this migration opportunistically as you touch list code.- Shared element transitions are worth adopting for your highest-traffic list-to-detail flow first, not 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 them yet unless you're explicitly piloting.