Shared elements with Navigation Compose
Stay organized with collections
Save and categorize content based on your preferences.
To use shared elements with the navigation-compose dependency, use the
Modifier.sharedElement() that takes an AnimatedVisibilityScope as a
parameter. You can use this to decide what should be visible and when.
The following is an example of using navigation-compose with shared elements:
@Preview
@Composable
funSharedElement_PredictiveBack(){
SharedTransitionLayout{
valnavController=rememberNavController()
NavHost(
navController=navController,
startDestination="home"
){
composable("home"){
HomeScreen(
this@SharedTransitionLayout,
this@composable,
{navController.navigate("details/$it")}
)
}
composable(
"details/{item}",
arguments=listOf(navArgument("item"){type=NavType.IntType})
){backStackEntry->
valid=backStackEntry.arguments?.getInt("item")
valsnack=listSnacks[id!!]
DetailsScreen(
id,
snack,
this@SharedTransitionLayout,
this@composable,
{
navController.navigate("home")
}
)
}
}
}
}
@Composable
funDetailsScreen(
id:Int,
snack:Snack,
sharedTransitionScope:SharedTransitionScope,
animatedContentScope:AnimatedContentScope,
onBackPressed:()->Unit
){
with(sharedTransitionScope){
Column(
Modifier
.fillMaxSize()
.clickable{
onBackPressed()
}
){
Image(
painterResource(id=snack.image),
contentDescription=snack.description,
contentScale=ContentScale.Crop,
modifier=Modifier
.sharedElement(
sharedTransitionScope.rememberSharedContentState(key="image-$id"),
animatedVisibilityScope=animatedContentScope
)
.aspectRatio(1f)
.fillMaxWidth()
)
Text(
snack.name,fontSize=18.sp,
modifier=
Modifier
.sharedElement(
sharedTransitionScope.rememberSharedContentState(key="text-$id"),
animatedVisibilityScope=animatedContentScope
)
.fillMaxWidth()
)
}
}
}
@Composable
funHomeScreen(
sharedTransitionScope:SharedTransitionScope,
animatedContentScope:AnimatedContentScope,
onItemClick:(Int)->Unit,
){
LazyColumn(
modifier=Modifier
.fillMaxSize()
.padding(8.dp),
verticalArrangement=Arrangement.spacedBy(8.dp)
){
itemsIndexed(listSnacks){index,item->
Row(
Modifier.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=animatedContentScope
)
.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=animatedContentScope,
)
)
}
}
}
}
}
dataclassSnack(
valname:String,
valdescription:String,
@DrawableResvalimage:Int
)
Predictive back with shared elements
To use predictive back with shared elements, follow these steps:
Use the latest
navigation-composedependency, using the snippet from the preceding section.dependencies{ defnav_version="2.8.0-beta02" implementation"androidx.navigation:navigation-compose:$nav_version" }Enable the Predictive back setting in developer options.
Add
android:enableOnBackInvokedCallback="true"to yourAndroidManifest.xmlfile:<manifestxmlns:android="http://schemas.android.com/apk/res/android"> <uses-permissionandroid:name="android.permission.INTERNET"/> <uses-permissionandroid:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28"/> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:enableOnBackInvokedCallback="true" android:theme="@style/Theme.Snippets">