Android Developers Blog
The latest Android and Google Play news for app and game developers.
🔍
Platform Android Studio Google Play Jetpack Kotlin Docs News

14 May 2024

What’s new in Jetpack Compose at I/O ‘24


Link copied to clipboard
Posted by Ben Trengrove – Developer Relations Engineer, and Nick Butcher – Product Manager for Jetpack Compose

Note: An earlier version of this post listed the changes coming to Compose as being in the \ release. This release will now be in July and we have updated this post accordingly.


At Google I/O 2024, we announced the upcoming July ‘24 Jetpack Compose release, packed with features designed to make Android development faster and easier, no matter what form factor you are building for. We also announced expanded Compose support across the ecosystem of Android devices. This post provides an overview of all the announcements, in case you missed any.

Compose July ‘24 release

Compose is Android's modern, native UI toolkit that is used by apps such as Threads, Google Drive, and SoundCloud. This release adds major features you have been asking for, including shared element transitions and list reordering animations, and improves performance.

Shared element transitions

Moving image of shared element transitions

Modifier.sharedElement() and Modifier.sharedBounds() have been added to Compose. They allow you to create beautiful transitions between screens with finer control than the View system allowed. Wrap your AnimatedContent composables in SharedTransitionLayout and then add the Modifier.sharedElement() or Modifier.sharedBounds() onto the content that you’d like to share between screens. Compose will then find composables with matching keys and smoothly transition between them.

Navigation Compose and predictive back animations in Android 15 also work smoothly together with shared element transitions. This allows you to create screen transitions directly tied to the navigation gesture, which provides a high quality user experience.

Check out the documentation for more information.

Lazy list item animations

Moving image of lazy list item animations

Lazy row and column now have the ability to automatically animate the insertion, removal, and reordering of items. Just add Modifier.animateItem() to your list items and changes will automatically animate. You can also customize the animation by providing different animation specifications.

Check out the documentation for the instructions.

Text

Text now supports inline links and basic HTML formatting via the new AnnotatedString.fromHtml() extension. This converts basic HTML formatting, including links to an AnnotatedString, which can then be rendered by Compose.

BasicTextField gains a new overload that accepts a TextFieldState; a new rich state object that allows more robust user experiences (such as rich content like keyboard gifs) and can be hoisted out of the component and updated asynchronously.

Note: Material TextField will be updated to use the new BasicTextField in a subsequent release, but if you’d like to try it out in your apps, see the documentation.

Contextual Flow Layouts

A commonly requested layout is a lazy flow layout that only composes the content that can fit. If you have ever needed this functionality, ContextualFlowRow and ContextualFlowColumn are for you. Given a max number of lines, the flow layout will compose as many items that can fit and then provide you the context of what was rendered. With this context, you can then render a custom expand indicator that shows a count of remaining items.

@OptIn(ExperimentalLayoutApi::class)
@Composable
private fun SuggestedSnacks(
   snacks: List<Snack>,
   onSnackClick: (Snack) -> Unit,
   modifier: Modifier = Modifier
) {
   var maxLines by remember { mutableIntStateOf(1) }
   ContextualFlowRow(
       maxLines = maxLines,
       overflow = ContextualFlowRowOverflow.expandIndicator {
           val remainingItems = totalItemCount - shownItemCount
           MyOverflowIndicator(
               remainingItems = remainingItems,
               modifier = Modifier
                   .clickable {
                       // Expand the max lines on click
                       maxLines += 1
                   }
           )
       },
       itemCount = snacks.size
   ) { index ->
       val snack = snacks[index]
       SnackItem(snack, onSnackClick)
   }
}

Image of Contextual flow layout in Jetsnack

Performance improvements

Jetpack Compose continues to get faster with every release. We are pleased to report that we have improved the time to first pixel benchmark of our Jetsnack sample by 17% compared to the January release. We gained these improvements simply by updating the sample app to the new Compose version. The chart below shows the improvement in Jetsnack with each Compose release, since the August 2023 release we have nearly halved the time to first pixel drawn of Jetsnack.

Bar graph showing Jetpack Compose speed increase from August 2023 - July 2024

The indication APIs have been rewritten to allow for lazy creation of ripples, which is very important for scroll performance. For most apps, there should be no changes required, but upgrading might introduce breaking changes if you have custom indications. For help with the migration, see the new documentation.

We continue to improve the efficiency of the Compose runtime, which speeds up all Compose code in your app. We’ve re-engineered the slot table to a more efficient data structure, and we are also generating more efficient code by detecting and removing unused composition groups. Additionally, there are new APIs that now allow you to customize the behavior of lazy layout prefetching.

Strong skipping mode

Strong skipping mode has graduated from experimental status and is now production-ready—the upcoming 2.0.20 compiler release will enable this feature by default. Strong skipping mode simplifies composable skipping by allowing composables with unstable parameters to be skipped. This means more composables will skip automatically, reducing the need to manually annotate classes as stable. The Now In Android sample saw a 20% improvement in home screen recomposition time when enabling strong skipping. For more details see the documentation.

Compose compiler moving to the Kotlin repository

In case you missed our previous announcement, the Compose compiler will be hosted in the Kotlin repository from Kotlin 2.0. This means you will no longer have to wait for a matching Compose compiler to be released to upgrade your Kotlin version. For full details on this change and to learn about the new Compose Compiler Gradle plugin, see our announcement blog post.

Stable APIs

We continue to stabilize experimental APIs and remove experimental annotations. Notable APIs for this release include Pager, AnchoredDraggable, SegmentedButton, SwipeToDismissBox, Slider, and more.

Compose support across Android form factors

We continue to extend Jetpack Compose to all Android form factors to make it faster and easier to build beautiful Android apps, no matter what Android form factor you are targeting. At I/O this year we announced a number of updates to support building layouts that adapt across screen sizes, Compose for TV reaching 1.0 Beta and updates to Compose for Wear OS.

Jetpack Libraries

Type safe navigation in Navigation Compose

As of Jetpack Navigation 2.8.0-alpha08, the Navigation Component has a full type safe system based on Kotlin Serialization for defining your navigation graph when using our Kotlin DSL, designed to work best with integrations like Navigation Compose.

Now, you can define your navigation destinations and parameters as serializable objects.

// Define a home destination that doesn't take any arguments
@Serializable
object Home

// Define a profile destination that takes an ID
@Serializable
data class Profile(val id: String)

Then, when defining your NavGraph, passing the object is enough. No more route strings!

NavHost(navController, startDestination = Home) {
    composable<Home> {
        HomeScreen(onNavigateToProfile = { id ->
            navController.navigate(Profile(id))
        })
     }
     composable<Profile> { backStackEntry ->
         val profile: Profile = backStackEntry.toRoute()
         ProfileScreen(profile)
     }
}

For more information, see this blog post.

CameraX Compose

We are releasing a new Compose-specific CameraX artifact called camera-viewfinder-compose. In this first alpha release, you can use the new Viewfinder composable to display a camera preview on your screen that always shows the correct aspect ratio and rotation, whether you resize your window, unfold your device, or change the display or orientation. It also correctly handles camera and surface lifecycles, something that can be difficult when dealing with cameras. It also enables complex interactions in the camera coordinate system, making it easy for you to implement gestures such as tap-to-focus or pinch-to-zoom.

You can use the Viewfinder composable even when you aren’t using any of the other CameraX libraries, and link it directly to your Camera2 code.

We are actively working on improving the APIs and are looking forward to your feedback! Check out the known issues, and raise bugs or feature requests to help us create the best possible camera experience in Compose.

Get started

We’re grateful for all of the bug reports and feature requests submitted to our issue tracker that led to these changes — they help us to improve Compose and build the APIs you need. Please continue providing your feedback, and help us make Compose better for you.

Wondering what’s next? Check out our roadmap to see the features we’re currently thinking about and working on. We can’t wait to see what you build.

Happy composing!