NavDisplay 提供内置动画功能,可在用户浏览应用时创建平滑的
视觉过渡效果。您可以使用
元数据在 NavDisplay 中全局自定义这些动画,也可以在 Scene 级自定义这些
动画。
了解内置动画功能
NavDisplay 使用 ContentTransform API 定义内容在导航期间的动画效果
。当从当前场景的类及其
key 属性派生的键发生变化时,NavDisplay 会自动为场景之间的转场添加动画效果。当此键发生变化时,NavDisplay 会使用过渡中相应场景的过渡类型(向前、向后或预测性返回)的 ContentTransform。如果未定义该 ContentTransform
,NavDisplay 会回退到使用其相应的 默认
过渡。
替换默认过渡
您可以通过向 NavDisplay 提供过渡参数来替换默认动画行为。
transitionSpec:此参数定义在将内容添加到返回堆栈时(即向前导航时)要应用的ContentTransform。popTransitionSpec:此参数定义在从返回堆栈中移除内容时(即向后导航时)要应用的ContentTransform。predictivePopTransitionSpec:此参数定义在使用预测性返回手势弹出内容时要应用的ContentTransform。
在 Scene 级替换过渡
您可以使用 元数据 为各个场景定义自定义动画,
方法是使用以下 元数据键 定义的 NavDisplay:
NavDisplay.TransitionKey:向前导航动画。NavDisplay.PopTransitionKey:向后导航动画。NavDisplay.PredictivePopTransitionKey:预测性返回动画。
如果提供了这些场景级过渡,则会使用它们,而不是 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 = 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) ) } } } }
在场景之间过渡导航条目
在使用场景创建自定义布局的应用中,
NavEntry 可能在过渡期间包含在两个场景的 entries 属性中。在内部,NavDisplay
会验证每个条目在任何时候最多显示在一个场景中,这可能会导致在呈现 NavEntry 的场景发生变化时出现跳跃式过渡。如需在场景之间平滑地为条目添加动画效果,您可以将NavDisplay封装在SharedTransitionLayout中,并将SharedTransitionScope提供给NavDisplay,如以下示例所示:
SharedTransitionLayout { NavDisplay( // ... sharedTransitionScope = this ) }
SharedTransitionScope 传递给 NavDisplay 时出现跳跃式过渡。SharedTransitionScope 传递给 NavDisplay 时出现平滑过渡。