Animer des transitions entre les destinations

NavDisplay fournit des fonctionnalités d'animation intégrées pour créer des transitions visuelles fluides lorsque les utilisateurs naviguent dans votre application. Vous pouvez personnaliser ces animations de manière globale pour le NavDisplay ou par NavEntry à l'aide de métadonnées.

Ignorer les transitions par défaut

NavDisplay utilise des ContentTransform pour définir l'animation du contenu pendant la navigation. Vous pouvez remplacer les comportements d'animation par défaut en fournissant des paramètres de transition à NavDisplay.

  • transitionSpec: ce paramètre définit le ContentTransform à appliquer lorsqu'un contenu est ajouté à la pile "Retour" (c'est-à-dire lors de la navigation vers l'avant).
  • popTransitionSpec: ce paramètre définit l'ContentTransform à appliquer lorsque du contenu est supprimé de la pile "Retour" (c'est-à-dire lors de la navigation "Retour").
  • predictivePopTransitionSpec: ce paramètre définit le ContentTransform à appliquer lorsque le contenu est extrait à l'aide d'un geste de retour prédictif.

Remplacer les transitions au niveau de chaque NavEntry

Vous pouvez également définir des animations personnalisées pour des NavEntry spécifiques à l'aide de leurs métadonnées. NavDisplay reconnaît des clés de métadonnées spéciales pour appliquer des transitions par entrée:

  • NavDisplay.transitionSpec: utilisez cette fonction d'assistance pour définir l'animation de navigation avant.
  • NavDisplay.popTransitionSpec: utilisez cette fonction d'assistance pour définir l'animation de navigation arrière pour un NavEntry spécifique.
  • NavDisplay.predictivePopTransitionSpec: utilisez cette fonction d'assistance pour définir l'animation des gestes de prévisualisation du Retour pour un NavEntry spécifique.

Ces transitions de métadonnées par entrée remplacent les transitions globales de NavDisplay du même nom.

L'extrait de code suivant illustre à la fois les transitions NavDisplay globales et un forçage au niveau de chaque 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)
                )
            }
        }
    }
}

Figure 1. Application avec des animations personnalisées.