Thành phần dùng chung với thành phần Điều hướng trong Compose

Để sử dụng các phần tử được chia sẻ với phần phụ thuộc navigation-compose, bạn có thể sử dụng các khái niệm tương tự như hiển thị trước đó: Sử dụng Modifier.sharedElement() lấy AnimatedVisibilityScope làm tham số. Bạn có thể sử dụng tính năng này để quyết định nội dung nào sẽ hiển thị và thời điểm hiển thị.

Hình 1. Điều hướng trong Compose có các phần tử dùng chung

Sau đây là ví dụ về cách sử dụng navigation-compose với các phần tử dùng chung:

@Preview
@Composable
fun SharedElement_PredictiveBack() {
    SharedTransitionLayout {
        val navController = rememberNavController()
        NavHost(
            navController = navController,
            startDestination = "home"
        ) {
            composable("home") {
                HomeScreen(
                    navController,
                    this@SharedTransitionLayout,
                    this@composable
                )
            }
            composable(
                "details/{item}",
                arguments = listOf(navArgument("item") { type = NavType.IntType })
            ) { backStackEntry ->
                val id = backStackEntry.arguments?.getInt("item")
                val snack = listSnacks[id!!]
                DetailsScreen(
                    navController,
                    id,
                    snack,
                    this@SharedTransitionLayout,
                    this@composable
                )
            }
        }
    }
}

@Composable
private fun DetailsScreen(
    navController: NavHostController,
    id: Int,
    snack: Snack,
    sharedTransitionScope: SharedTransitionScope,
    animatedContentScope: AnimatedContentScope
) {
    with(sharedTransitionScope) {
        Column(
            Modifier
                .fillMaxSize()
                .clickable {
                    navController.navigate("home")
                }
        ) {
            Image(
                painterResource(id = snack.image),
                contentDescription = snack.description,
                contentScale = ContentScale.Crop,
                modifier = Modifier.Companion
                    .sharedElement(
                        sharedTransitionScope.rememberSharedContentState(key = "image-$id"),
                        animatedVisibilityScope = animatedContentScope
                    )
                    .aspectRatio(1f)
                    .fillMaxWidth()
            )
            Text(
                snack.name, fontSize = 18.sp,
                modifier =
                Modifier.Companion
                    .sharedElement(
                        sharedTransitionScope.rememberSharedContentState(key = "text-$id"),
                        animatedVisibilityScope = animatedContentScope
                    )
                    .fillMaxWidth()
            )
        }
    }
}

@Composable
private fun HomeScreen(
    navController: NavHostController,
    sharedTransitionScope: SharedTransitionScope,
    animatedContentScope: AnimatedContentScope
) {
    LazyColumn(
        modifier = Modifier
            .fillMaxSize()
            .padding(8.dp),
        verticalArrangement = Arrangement.spacedBy(8.dp)
    ) {
        itemsIndexed(listSnacks) { index, item ->
            Row(
                Modifier.clickable {
                    navController.navigate("details/$index")
                }
            ) {
                Spacer(modifier = Modifier.width(8.dp))
                with(sharedTransitionScope) {
                    Image(
                        painterResource(id = item.image),
                        contentDescription = item.description,
                        contentScale = ContentScale.Crop,
                        modifier = Modifier.Companion
                            .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
)

Xem trước thao tác quay lại bằng các thành phần được chia sẻ

Nếu bạn muốn sử dụng tính năng xem trước thao tác quay lại với các phần tử được chia sẻ, hãy đảm bảo bạn đang sử dụng phần phụ thuộc navigation-compose mới nhất bằng cách sử dụng đoạn mã từ phần trước.

dependencies {
    def nav_version = "2.8.0-beta02"

    implementation "androidx.navigation:navigation-compose:$nav_version"
}

Thêm android:enableOnBackInvokedCallback="true" vào tệp AndroidManifest.xml để bật tính năng xem trước thao tác quay lại:

<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">
Hình 2. Điều hướng trong Compose với tính năng Xem trước thao tác quay lại