Các phần tử dùng chung giúp quá trình chuyển đổi giữa các màn hình diễn ra mượt mà và hấp dẫn hơn bằng cách tạo mối liên kết trực quan hướng dẫn người dùng. Hướng dẫn này minh hoạ cách sử dụng các API phần tử dùng chung với cả thư viện Navigation 3 và Navigation 2 của Jetpack.
Đoạn mã sau đây bao gồm các thành phần kết hợp DetailsScreen và HomeScreen đóng vai trò là đích đến mà người dùng có thể di chuyển giữa các đích đến. Trong mỗi màn hình, bộ sửa đổi sharedElement được dùng cho cả hình ảnh và văn bản để mỗi phần tử trong số đó có thể độc lập tạo ảnh động giữa các màn hình.
@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
Để sử dụng API phần tử dùng chung với Navigation 3, trước tiên, bạn phải bao bọc NavDisplay của ứng dụng trong một SharedTransitionLayout. Sau đó, bạn có thể truyền SharedTransitionScope được cung cấp cho các thành phần kết hợp màn hình.
Đối với AnimatedVisibilityScope, hãy sử dụng thành phần Compose LocalNavAnimatedContentScope cục bộ cung cấp AnimatedContentScope từ AnimatedContent mà NavDisplay sử dụng nội bộ để tạo hiệu ứng chuyển động giữa các cảnh.
@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() }, ) } }) } }
Navigation 2
Để sử dụng API phần tử dùng chung với Navigation 2, trước tiên, bạn phải bao bọc NavHost của ứng dụng trong một SharedTransitionLayout. Sau đó, bạn có thể truyền SharedTransitionScope đã cung cấp đến các thành phần kết hợp màn hình.
Tham số content của trình tạo composable dùng AnimatedContentScope làm đối tượng nhận, nên bạn có thể dùng this@composable để tham chiếu phạm vi đó.
@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() } ) } } } }
Xem trước thao tác quay lại bằng các phần tử dùng chung
Để sử dụng tính năng xem trước thao tác quay lại với các phần tử dùng chung, hãy làm theo các bước sau:
Tất cả các phiên bản của Navigation 3 đều hỗ trợ tính năng xem trước thao tác quay lại. Đối với Navigation 2, hãy sử dụng bản phát hành
2.8.0-alpha02củanavigation-composehoặc phiên bản mới hơn:[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) }Ảnh động xem trước thao tác quay lại được bật theo mặc định trên những thiết bị chạy Android 15 (cấp độ API 35) trở lên. Đối với các thiết bị chạy Android 14 (cấp độ API 34), bạn cần bật chế độ cài đặt Xem trước thao tác quay lại trong các tuỳ chọn cho nhà phát triển.
Nếu ứng dụng của bạn nhắm đến Android 14 trở xuống, bạn phải thêm
android:enableOnBackInvokedCallback="true"vào<application>hoặc các phần tử<activity>cụ thể trong tệpAndroidManifest.xml. Bạn không cần cờ này nếu ứng dụng của bạn nhắm đến Android 15 trở lên.<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <application ... android:enableOnBackInvokedCallback="true"> </application> </manifest>