Tạo ảnh động giữa các đích đến

NavDisplay cung cấp các chức năng ảnh động tích hợp để tạo hiệu ứng chuyển đổi mượt mà về mặt hình ảnh khi người dùng di chuyển trong ứng dụng của bạn. Bạn có thể tuỳ chỉnh các ảnh động này trên toàn cục cho NavDisplay hoặc ở cấp Scene bằng cách sử dụng siêu dữ liệu.

Tìm hiểu các chức năng ảnh động tích hợp sẵn

NavDisplay sử dụng API ContentTransform để xác định cách nội dung chuyển động trong quá trình điều hướng. NavDisplay tự động tạo hiệu ứng chuyển đổi giữa các cảnh khi một khoá bắt nguồn từ lớp của cảnh hiện tại và thuộc tính key của cảnh đó thay đổi. Khi khoá này thay đổi, NavDisplay sẽ dùng ContentTransform cho loại hiệu ứng chuyển cảnh (chuyển tiếp, quay lại hoặc quay lại dự đoán) từ cảnh thích hợp trong hiệu ứng chuyển cảnh. Nếu bạn không xác định ContentTransform, thì NavDisplay sẽ quay lại sử dụng chuyển cảnh mặc định tương ứng.

Ghi đè hiệu ứng chuyển cảnh mặc định

Bạn có thể ghi đè các hành vi mặc định của ảnh động bằng cách cung cấp các tham số chuyển đổi cho NavDisplay.

  • transitionSpec: Tham số này xác định ContentTransform cần áp dụng khi nội dung được thêm vào ngăn xếp lui (tức là khi di chuyển về phía trước).
  • popTransitionSpec: Tham số này xác định ContentTransform cần áp dụng khi nội dung bị xoá khỏi ngăn xếp lui (tức là khi điều hướng quay lại).
  • predictivePopTransitionSpec: Tham số này xác định ContentTransform cần áp dụng khi nội dung xuất hiện bằng cử chỉ xem trước thao tác quay lại.

Ghi đè hiệu ứng chuyển cảnh ở cấp Scene

Bạn có thể sử dụng siêu dữ liệu để xác định các ảnh động tuỳ chỉnh cho từng cảnh bằng cách sử dụng các khoá siêu dữ liệu sau do NavDisplay xác định:

Khi được cung cấp, những hiệu ứng chuyển cảnh này sẽ được dùng thay cho các giá trị mặc định tương ứng được đặt trên NavDisplay.

Đoạn mã sau đây minh hoạ cả hiệu ứng chuyển đổi NavDisplay trên toàn cục và một chế độ ghi đè ở cấp NavEntry riêng lẻ:

@Serializable
data object ScreenA : NavKey

@Serializable
data object ScreenB : NavKey

@Serializable
data object ScreenC : NavKey

class AnimatedNavDisplayActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {

            Scaffold { paddingValues ->

                val backStack = rememberNavBackStack(ScreenA)

                NavDisplay(
                    backStack = backStack,
                    onBack = { backStack.removeLastOrNull() },
                    entryProvider = entryProvider {
                        entry<ScreenA> {
                            ContentOrange("This is Screen A") {
                                Button(onClick = { backStack.add(ScreenB) }) {
                                    Text("Go to Screen B")
                                }
                            }
                        }
                        entry<ScreenB> {
                            ContentMauve("This is Screen B") {
                                Button(onClick = { backStack.add(ScreenC) }) {
                                    Text("Go to Screen C")
                                }
                            }
                        }
                        entry<ScreenC>(
                            metadata = metadata {
                                put(NavDisplay.TransitionKey) {
                                    // Slide new content up, keeping the old content in place underneath
                                    slideInVertically(
                                        initialOffsetY = { it },
                                        animationSpec = tween(1000)
                                    ) togetherWith ExitTransition.KeepUntilTransitionsFinished
                                }
                                put(NavDisplay.PopTransitionKey) {
                                    // Slide old content down, revealing the new content in place underneath
                                    EnterTransition.None togetherWith
                                            slideOutVertically(
                                                targetOffsetY = { it },
                                                animationSpec = tween(1000)
                                            )
                                }
                                put(NavDisplay.PredictivePopTransitionKey) {
                                    // Slide old content down, revealing the new content in place underneath
                                    EnterTransition.None togetherWith
                                            slideOutVertically(
                                                targetOffsetY = { it },
                                                animationSpec = tween(1000)
                                            )
                                }
                            }
                        ) {
                            ContentGreen("This is Screen C")
                        }
                    },
                    transitionSpec = {
                        // Slide in from right when navigating forward
                        slideInHorizontally(initialOffsetX = { it }) togetherWith
                            slideOutHorizontally(targetOffsetX = { -it })
                    },
                    popTransitionSpec = {
                        // Slide in from left when navigating back
                        slideInHorizontally(initialOffsetX = { -it }) togetherWith
                            slideOutHorizontally(targetOffsetX = { it })
                    },
                    predictivePopTransitionSpec = {
                        // Slide in from left when navigating back
                        slideInHorizontally(initialOffsetX = { -it }) togetherWith
                            slideOutHorizontally(targetOffsetX = { it })
                    },
                    modifier = Modifier.padding(paddingValues)
                )
            }
        }
    }
}

Hình 1. Ứng dụng có ảnh động tuỳ chỉnh.

Chuyển đổi các mục điều hướng giữa các cảnh

Trong các ứng dụng tạo bố cục tuỳ chỉnh bằng cảnh, có thể NavEntry sẽ được đưa vào thuộc tính entries của cả hai cảnh trong quá trình chuyển cảnh. Về nội bộ, NavDisplay xác minh rằng mỗi mục được hiển thị tối đa trong một cảnh tại bất kỳ thời điểm nào. Điều này có thể dẫn đến các hiệu ứng chuyển cảnh giật cục khi cảnh kết xuất NavEntry thay đổi. Để tạo hiệu ứng chuyển động mượt mà cho các mục giữa các cảnh, bạn có thể gói NavDisplay trong SharedTransitionLayout và cung cấp SharedTransitionScope cho NavDisplay như minh hoạ trong ví dụ sau:

SharedTransitionLayout {
    NavDisplay(
        // ...
        sharedTransitionScope = this
    )
}