Elemen bersama membuat transisi antar-layar lebih lancar dan menarik dengan membuat koneksi visual yang memandu pengguna. Panduan ini menunjukkan cara menggunakan API elemen bersama dengan library Jetpack Navigation 3 dan Navigation 2.
Cuplikan berikut menyertakan composable DetailsScreen dan HomeScreen yang berfungsi sebagai tujuan yang dapat dinavigasi pengguna. Dalam setiap layar, pengubah
sharedElement digunakan pada gambar dan teks sehingga
setiap elemen tersebut secara independen dianimasikan antar-layar.
@Composable fun DetailsScreen( id: Int, snack: Snack, sharedTransitionScope: SharedTransitionScope, animatedVisibilityScope: AnimatedVisibilityScope, onBackPressed: () -> Unit ) { with(sharedTransitionScope) { Column( modifier = Modifier .fillMaxSize() .clickable { onBackPressed() }, ) { Image( painterResource(id = snack.image), contentDescription = snack.description, contentScale = ContentScale.Crop, modifier = Modifier .sharedElement( sharedTransitionScope.rememberSharedContentState(key = "image-$id"), animatedVisibilityScope = animatedVisibilityScope ) .aspectRatio(1f) .fillMaxWidth() ) Text( text = snack.name, fontSize = 18.sp, modifier = Modifier .sharedElement( sharedTransitionScope.rememberSharedContentState(key = "text-$id"), animatedVisibilityScope = animatedVisibilityScope ) .fillMaxWidth(), ) } } } @Composable fun HomeScreen( sharedTransitionScope: SharedTransitionScope, animatedVisibilityScope: AnimatedVisibilityScope, onItemClick: (Int) -> Unit, ) { LazyColumn( modifier = Modifier .fillMaxSize() .padding(8.dp), verticalArrangement = Arrangement.spacedBy(8.dp) ) { itemsIndexed(listSnacks) { index, item -> Row( modifier = Modifier .fillMaxWidth() .clickable { onItemClick(index) }, ) { Spacer(modifier = Modifier.width(8.dp)) with(sharedTransitionScope) { Image( painterResource(id = item.image), contentDescription = item.description, contentScale = ContentScale.Crop, modifier = Modifier .sharedElement( sharedTransitionScope.rememberSharedContentState(key = "image-$index"), animatedVisibilityScope = animatedVisibilityScope ) .size(100.dp) ) Spacer(modifier = Modifier.width(8.dp)) Text( item.name, fontSize = 18.sp, modifier = Modifier .align(Alignment.CenterVertically) .sharedElement( sharedTransitionScope.rememberSharedContentState(key = "text-$index"), animatedVisibilityScope = animatedVisibilityScope, ) ) } } } } }
Navigation 3
Untuk menggunakan API elemen bersama dengan Navigation 3, Anda harus terlebih dahulu menggabungkan aplikasi Anda
NavDisplay dalam SharedTransitionLayout. Kemudian, Anda dapat meneruskan
yang disediakan SharedTransitionScope ke composable layar.
Untuk AnimatedVisibilityScope, gunakan
LocalNavAnimatedContentScope komposisi lokal yang menyediakan
AnimatedContentScope dari AnimatedContent yang NavDisplay
digunakan secara internal untuk menganimasikan antar-adegan.
@Composable fun SharedElement_Nav3() { SharedTransitionLayout { val backStack = rememberNavBackStack(HomeRoute) // Note: NavDisplay accepts a `sharedTransitionScope` parameter, which is used to animate // NavEntry instances between scenes. This parameter *isn't* required for shared element // or shared bounds transitioning elements between different NavEntry, as demonstrated in // this sample. // See https://developer.android.com/guide/navigation/navigation-3/animate-destinations#transition-nav-entries NavDisplay( modifier = Modifier.safeDrawingPadding(), backStack = backStack, entryProvider = entryProvider { entry<HomeRoute> { HomeScreen( sharedTransitionScope = this@SharedTransitionLayout, animatedVisibilityScope = LocalNavAnimatedContentScope.current, onItemClick = { backStack.add(DetailsRoute(it)) }) } entry<DetailsRoute> { detailsRoute -> val id = detailsRoute.item val snack = listSnacks[id] DetailsScreen( id = id, snack = snack, sharedTransitionScope = this@SharedTransitionLayout, animatedVisibilityScope = LocalNavAnimatedContentScope.current, onBackPressed = { backStack.removeLastOrNull() }, ) } }) } }
Navigation 2
Untuk menggunakan API elemen bersama dengan Navigation 2, Anda harus terlebih dahulu menggabungkan aplikasi Anda
NavHost dalam SharedTransitionLayout. Kemudian, Anda dapat meneruskan SharedTransitionScope yang disediakan ke composable layar.
Parameter content dari builder composable menggunakan
AnimatedContentScope sebagai penerima, sehingga Anda dapat menggunakan this@composable untuk
mereferensikan cakupan tersebut.
@Composable fun SharedElement_Nav2() { SharedTransitionLayout { val navController = rememberNavController() NavHost( navController = navController, startDestination = "home", modifier = Modifier.safeDrawingPadding() ) { composable("home") { HomeScreen( sharedTransitionScope = this@SharedTransitionLayout, animatedVisibilityScope = this@composable, onItemClick = { navController.navigate("details/$it") }) } composable( "details/{item}", arguments = listOf(navArgument("item") { type = NavType.IntType }) ) { backStackEntry -> val id = backStackEntry.arguments?.getInt("item") ?: 0 val snack = listSnacks[id] DetailsScreen( id = id, snack = snack, sharedTransitionScope = this@SharedTransitionLayout, animatedVisibilityScope = this@composable, onBackPressed = { navController.popBackStack() } ) } } } }
Kembali prediktif dengan elemen bersama
Untuk menggunakan kembali prediktif dengan elemen bersama, ikuti langkah-langkah berikut:
Semua versi Navigation 3 mendukung kembali prediktif. Untuk Navigation 2, gunakan rilis
2.8.0-alpha02darinavigation-composeatau yang lebih baru:[versions] androidx-navigation = "2.8.0-alpha02" # Or newer [libraries] androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "androidx-navigation" }dependencies { implementation(libs.androidx.navigation.compose) }Animasi kembali prediktif diaktifkan secara default di perangkat yang menjalankan Android 15 (level API 35) atau yang lebih tinggi. Untuk perangkat yang menjalankan Android 14 (level API 34), Anda harus mengaktifkan setelan Kembali prediktif di opsi developer.
Jika aplikasi Anda menargetkan Android 14 atau yang lebih rendah, Anda harus menambahkan
android:enableOnBackInvokedCallback="true"ke<application>atau elemen<activity>tertentu dalam fileAndroidManifest.xml. Anda tidak memerlukan flag ini jika aplikasi Anda menargetkan Android 15 atau yang lebih tinggi.<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <application ... android:enableOnBackInvokedCallback="true"> </application> </manifest>