使用 Navigation Compose 构建共享元素

如需将共享元素与 navigation-compose 依赖项搭配使用,请使用将 AnimatedVisibilityScope 作为参数的 Modifier.sharedElement()。您可以使用此属性来决定应显示哪些内容以及何时显示。

图 1. 使用共享元素的 Navigation Compose。

以下示例展示了如何将 navigation-compose 与共享元素搭配使用:

@Preview @Composable fun SharedElement_PredictiveBack() {  SharedTransitionLayout {  val navController = 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 ->  val id = backStackEntry.arguments?.getInt("item")  val snack = listSnacks[id!!]  DetailsScreen(  id,  snack,  this@SharedTransitionLayout,  this@composable,  {  navController.navigate("home")  }  )  }  }  } } @Composable fun DetailsScreen(  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 fun HomeScreen(  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,  )  )  }  }  }  } } data class Snack(  val name: String,  val description: String,  @DrawableRes val image: Int )

使用共享元素的预测性返回

如需将预测性返回与共享元素搭配使用,请按以下步骤操作:

  1. 使用上一部分中的代码段,使用最新的 navigation-compose 依赖项

    dependencies {  def nav_version = "2.8.0-beta02"  implementation "androidx.navigation:navigation-compose:$nav_version" } 
  2. 在开发者选项中启用预测性返回设置

  3. android:enableOnBackInvokedCallback="true" 添加到 AndroidManifest.xml 文件中:

    <manifest xmlns:android="http://schemas.android.com/apk/res/android">  <uses-permission android:name="android.permission.INTERNET" />  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />  <uses-permission android: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"> 
图 2. Navigation Compose 与预测性返回功能搭配使用。