Elemen bersama membuat transisi antarlayar lebih lancar dan menarik dengan membuat hubungan visual yang memandu pengguna. Panduan ini menunjukkan cara menggunakan API elemen bersama dengan library Jetpack Navigation 3 dan Navigation 2.
Cuplikan berikut mencakup 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 dapat dianimasikan secara independen 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 membungkus
NavDisplay aplikasi dalam SharedTransitionLayout terlebih dahulu. Kemudian, Anda dapat meneruskan
SharedTransitionScope yang diberikan ke composable layar.
Untuk AnimatedVisibilityScope, gunakan lokal komposisi
LocalNavAnimatedContentScope yang menyediakan
AnimatedContentScope dari AnimatedContent yang digunakan
NavDisplay 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() }, ) } }) } }
Navigasi 2
Untuk menggunakan API elemen bersama dengan Navigation 2, Anda harus membungkus
NavHost aplikasi dalam SharedTransitionLayout terlebih dahulu. Kemudian, Anda dapat meneruskan
SharedTransitionScope yang diberikan ke composable layar.
Parameter content 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-alpha02navigation-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 elemen<application>atau<activity>tertentu dalam fileAndroidManifest.xml. Anda tidak memerlukan tanda 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>