在目的地之间添加动画效果

NavDisplay 提供了内置的动画功能,可在用户在应用中导航时创建流畅的视觉过渡。您可以为 NavDisplay 全局自定义这些动画,也可以使用元数据为每个 NavEntry 单独自定义这些动画。

替换默认过渡效果

NavDisplay 使用 ContentTransform 定义内容在导航期间的动画方式。您可以通过向 NavDisplay 提供过渡参数来替换默认的动画行为。

  • transitionSpec:此参数定义当内容添加到返回堆栈时(即向前导航时)要应用的 ContentTransform
  • popTransitionSpec:此参数定义当内容从返回堆栈中移除时(即向后导航时)要应用的 ContentTransform
  • predictivePopTransitionSpec:此参数定义当内容通过预测性返回手势弹出时要应用的 ContentTransform

在各个 NavEntry 级别替换过渡效果

您还可以使用元数据为特定的 NavEntry 定义自定义动画。NavDisplay 可识别特殊的元数据键来应用每个条目的过渡效果。

  • NavDisplay.transitionSpec:使用此辅助函数定义向前导航动画。
  • NavDisplay.popTransitionSpec:使用此辅助函数定义特定 NavEntry 的向后导航动画。
  • NavDisplay.predictivePopTransitionSpec:使用此辅助函数定义特定 NavEntry 的预测性返回手势动画。

这些每条目元数据过渡效果会替换 NavDisplay 中同名的全局过渡效果。

以下代码段演示了全局 NavDisplay 过渡效果以及在各个 NavEntry 级别的替换。

@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 = NavDisplay.transitionSpec {
                                // Slide new content up, keeping the old content in place underneath
                                slideInVertically(
                                    initialOffsetY = { it },
                                    animationSpec = tween(1000)
                                ) togetherWith ExitTransition.KeepUntilTransitionsFinished
                            } + NavDisplay.popTransitionSpec {
                                // Slide old content down, revealing the new content in place underneath
                                EnterTransition.None togetherWith
                                    slideOutVertically(
                                        targetOffsetY = { it },
                                        animationSpec = tween(1000)
                                    )
                            } + NavDisplay.predictivePopTransitionSpec {
                                // 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)
                )
            }
        }
    }
}

图 1. 具有自定义动画效果的应用。