Công thức về ảnh động

Công thức này cho biết cách ghi đè các ảnh động mặc định ở cấp NavDisplay và ở cấp đích đến riêng lẻ.

Cách hoạt động

Thành phần kết hợp NavDisplay nhận các tham số transitionSpec, popTransitionSpecpredictivePopTransitionSpec để xác định ảnh động cho thao tác điều hướng tiến, lùi và vuốt ngược dự đoán tương ứng. Theo mặc định, các ảnh động này sẽ được áp dụng cho tất cả các đích đến.

Trong ví dụ này, chúng ta sử dụng slideInHorizontallyslideOutHorizontally để tạo ảnh động trượt cho thao tác điều hướng tiến và lùi.

Bạn cũng có thể ghi đè các ảnh động này cho một đích đến cụ thể bằng cách cung cấp một transitionSpecpopTransitionSpec khác cho thành phần kết hợp entry. Trong công thức này, ScreenC có một ảnh động trượt dọc tuỳ chỉnh.

package com.example.nav3recipes.animations


import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.animation.EnterTransition
import androidx.compose.animation.ExitTransition
import androidx.compose.animation.core.tween
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.slideOutVertically
import androidx.compose.animation.togetherWith
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.lifecycle.compose.dropUnlessResumed
import androidx.navigation3.runtime.NavKey
import androidx.navigation3.runtime.entryProvider
import androidx.navigation3.runtime.metadata
import androidx.navigation3.runtime.rememberNavBackStack
import androidx.navigation3.ui.NavDisplay
import com.example.nav3recipes.content.ContentGreen
import com.example.nav3recipes.content.ContentMauve
import com.example.nav3recipes.content.ContentOrange
import com.example.nav3recipes.ui.setEdgeToEdgeConfig
import kotlinx.serialization.Serializable


@Serializable
private data object ScreenA : NavKey

@Serializable
private data object ScreenB : NavKey

@Serializable
private data object ScreenC : NavKey


class AnimatedActivity : ComponentActivity() {

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

            val backStack = rememberNavBackStack(ScreenA)

            NavDisplay(
                backStack = backStack,
                onBack = { backStack.removeLastOrNull() },
                entryProvider = entryProvider {
                    entry<ScreenA> {
                        ContentOrange("This is Screen A") {
                            Button(onClick = dropUnlessResumed { backStack.add(ScreenB) }) {
                                Text("Go to Screen B")
                            }
                        }
                    }
                    entry<ScreenB> {
                        ContentMauve("This is Screen B") {
                            Button(onClick = dropUnlessResumed { backStack.add(ScreenC) }) {
                                Text("Go to Screen C")
                            }
                        }
                    }
                    entry<ScreenC>(
                        metadata = metadata {
                            // Slide new content up, keeping the old content in place underneath
                            put(NavDisplay.TransitionKey) {
                                slideInVertically(
                                    initialOffsetY = { it },
                                    animationSpec = tween(1000)
                                ) togetherWith ExitTransition.KeepUntilTransitionsFinished
                            }

                            // Slide old content down, revealing the new content in place underneath
                            put(NavDisplay.PopTransitionKey) {
                                EnterTransition.None togetherWith
                                        slideOutVertically(
                                            targetOffsetY = { it },
                                            animationSpec = tween(1000)
                                        )
                            }

                            // Slide old content down, revealing the new content in place underneath
                            put(NavDisplay.PredictivePopTransitionKey) {
                                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 },
                        animationSpec = tween(1000)
                    ) togetherWith slideOutHorizontally(
                        targetOffsetX = { -it },
                        animationSpec = tween(1000)
                    )
                },
                popTransitionSpec = {
                    // Slide in from left when navigating back
                    slideInHorizontally(
                        initialOffsetX = { -it },
                        animationSpec = tween(1000)
                    ) togetherWith slideOutHorizontally(
                        targetOffsetX = { it },
                        animationSpec = tween(1000)
                    )
                },
                predictivePopTransitionSpec = {
                    // Slide in from left when navigating back
                    slideInHorizontally(
                        initialOffsetX = { -it },
                        animationSpec = tween(1000)
                    ) togetherWith slideOutHorizontally(
                        targetOffsetX = { it },
                        animationSpec = tween(1000)
                    )
                }
            )
        }
    }
}