Gli elementi condivisi rendono le transizioni tra le schermate più fluide e coinvolgenti creando una connessione visiva che guida l'utente. Questa guida mostra come utilizzare le API per gli elementi condivisi con le librerie Jetpack Navigation 3 e Navigation 2.
Il seguente snippet include i composable DetailsScreen e HomeScreen che fungono da destinazioni tra cui gli utenti possono spostarsi. All'interno di ogni schermata, il modificatore
sharedElement viene utilizzato sia sull'immagine sia sul testo, in modo che
ciascuno di questi elementi venga animato in modo indipendente tra le schermate.
@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, ) ) } } } } }
Navigazione 3
Per utilizzare le API degli elementi condivisi con Navigation 3, devi prima racchiudere NavDisplay della tua app in un SharedTransitionLayout. Puoi quindi passare il
SharedTransitionScope fornito ai composable dello schermo.
Per AnimatedVisibilityScope, utilizza la composizione locale LocalNavAnimatedContentScope che fornisce AnimatedContentScope da AnimatedContent che NavDisplay utilizza internamente per animare le scene.
@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() }, ) } }) } }
Navigazione 2
Per utilizzare le API degli elementi condivisi con Navigation 2, devi prima racchiudere il
NavHost della tua app in un SharedTransitionLayout. Puoi quindi passare il SharedTransitionScope fornito ai composable dello schermo.
Il parametro content del builder composable utilizza
AnimatedContentScope come destinatario, quindi puoi utilizzare this@composable per
fare riferimento a questo ambito.
@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() } ) } } } }
Indietro predittivo con elementi condivisi
Per utilizzare Indietro predittivo con gli elementi condivisi:
Tutte le versioni di Navigation 3 supportano la funzionalità Indietro predittivo. Per Navigation 2, utilizza la versione
2.8.0-alpha02dinavigation-composeo versioni successive:[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) }Le animazioni di Indietro predittivo sono attive per impostazione predefinita sui dispositivi con Android 15 (livello API 35) o versioni successive. Per i dispositivi con Android 14 (livello API 34), devi attivare l'impostazione Indietro predittivo nelle opzioni sviluppatore.
Se la tua app ha come target Android 14 o versioni precedenti, devi aggiungere
android:enableOnBackInvokedCallback="true"agli elementi<application>o<activity>specifici nel fileAndroidManifest.xml. Non hai bisogno di questo flag se la tua app ha come target Android 15 o versioni successive.<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <application ... android:enableOnBackInvokedCallback="true"> </application> </manifest>