NavDisplay provides built-in animation capabilities to create smooth visual transitions as users navigate through your app. You can customize these animations globally for the NavDisplay or on a per-NavEntry basis using metadata.
Override default transitions
NavDisplay uses ContentTransforms to define how content animates during navigation. You can override the default animation behaviors by providing transition parameters to NavDisplay.
transitionSpec: This parameter defines theContentTransformto apply when content is added to the back stack (i.e., when navigating forward).popTransitionSpec: This parameter defines theContentTransformto apply when content is removed from the back stack (i.e., when navigating back).predictivePopTransitionSpec: This parameter defines theContentTransformto apply when content is popped using a predictive back gesture.
Override transitions at the individual NavEntry level
You can also define custom animations for specific NavEntrys using their metadata. NavDisplay recognizes special metadata keys to apply per-entry transitions:
NavDisplay.transitionSpec: Use this helper function to define the forward navigation animation.NavDisplay.popTransitionSpec: Use this helper function to define the backward navigation animation for a specificNavEntry.NavDisplay.predictivePopTransitionSpec: Use this helper function to define the animation for predictive back gestures for a specificNavEntry.
These per-entry metadata transitions override the NavDisplay's global transitions of the same name.
The following snippet demonstrates both global NavDisplay transitions and an override at the individual NavEntry level:
@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) ) } } } }