องค์ประกอบที่แชร์ทำให้การเปลี่ยนผ่านระหว่างหน้าจอราบรื่นและน่าสนใจยิ่งขึ้นด้วยการ สร้างการเชื่อมต่อด้วยภาพที่จะนำทางผู้ใช้ คู่มือนี้แสดงวิธี ใช้ Shared Element API กับทั้งไลบรารี Navigation 3 และ Navigation 2 ของ Jetpack
ข้อมูลโค้ดต่อไปนี้มี Composable DetailsScreen และ HomeScreen ซึ่งทำหน้าที่เป็นปลายทางที่ผู้ใช้ไปยังส่วนต่างๆ ได้ ภายในแต่ละหน้าจอ ระบบจะใช้ตัวแก้ไข
sharedElement กับทั้งรูปภาพและข้อความเพื่อให้
องค์ประกอบแต่ละรายการเคลื่อนไหวอย่างอิสระระหว่างหน้าจอ
@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, ) ) } } } } }
การนำทาง 3
หากต้องการใช้ API ขององค์ประกอบที่แชร์กับ Navigation 3 คุณต้องห่อ NavDisplay ของแอปใน SharedTransitionLayout ก่อน จากนั้นคุณจะส่ง SharedTransitionScope ที่ระบุไปยัง Composable ของหน้าจอได้
สำหรับ AnimatedVisibilityScope ให้ใช้การจัดองค์ประกอบ LocalNavAnimatedContentScope ในเครื่องซึ่งมี AnimatedContentScope จาก AnimatedContent ที่ NavDisplay
ใช้ภายในเพื่อเปลี่ยนฉาก
@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() }, ) } }) } }
การนำทาง 2
หากต้องการใช้ API ขององค์ประกอบที่แชร์กับ Navigation 2 คุณต้องห่อหุ้ม NavHost ของแอปใน SharedTransitionLayout ก่อน จากนั้นคุณจะส่ง SharedTransitionScope ที่ระบุไปยัง Composable ของหน้าจอได้
พารามิเตอร์ content ของเครื่องมือสร้าง composable ใช้ AnimatedContentScope เป็นตัวรับ ดังนั้นคุณจึงใช้ this@composable เพื่อ
อ้างอิงขอบเขตนั้นได้
@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() } ) } } } }
การย้อนกลับที่คาดการณ์ได้พร้อมองค์ประกอบที่แชร์
หากต้องการใช้การย้อนกลับที่คาดการณ์ได้กับองค์ประกอบที่แชร์ ให้ทำตามขั้นตอนต่อไปนี้
การนำทาง 3 ทุกเวอร์ชันรองรับการย้อนกลับที่คาดการณ์ได้ สำหรับ Navigation 2 ให้ใช้
2.8.0-alpha02รุ่นnavigation-composeหรือใหม่กว่า[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) }ภาพเคลื่อนไหวการย้อนกลับที่คาดการณ์ได้จะเปิดใช้โดยค่าเริ่มต้นในอุปกรณ์ที่ใช้ Android 15 (ระดับ API 35) ขึ้นไป สำหรับอุปกรณ์ที่ใช้ Android 14 (ระดับ API 34) คุณต้องเปิดใช้การย้อนกลับที่คาดการณ์ได้ในตัวเลือกสำหรับนักพัฒนาแอป
หากแอปกำหนดเป้าหมายเป็น Android 14 หรือต่ำกว่า คุณต้องเพิ่ม
android:enableOnBackInvokedCallback="true"ลงใน<application>หรือ องค์ประกอบ<activity>ที่เฉพาะเจาะจงในไฟล์AndroidManifest.xmlคุณไม่ จำเป็นต้องใช้ Flag นี้หากแอปกำหนดเป้าหมายเป็น Android 15 ขึ้นไป<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <application ... android:enableOnBackInvokedCallback="true"> </application> </manifest>