Animowanie przejścia między miejscami docelowymi

NavDisplay udostępnia wbudowane funkcje animacji, które umożliwiają tworzenie płynnych wizualnych przejść podczas poruszania się użytkowników po aplikacji. Możesz dostosowywać te animacje globalnie w NavDisplay lub w poszczególnych NavEntry za pomocą metadanych.

Zastępowanie domyślnych przejść

NavDisplay używa ContentTransform, aby określić sposób animowania treści podczas nawigacji. Aby zastąpić domyślne zachowanie animacji, podaj parametry przejścia w tagu NavDisplay.

  • transitionSpec: ten parametr określa ContentTransform, który ma być stosowany, gdy do stosu (tzn. podczas przechodzenia do przodu) dodawane są treści.
  • popTransitionSpec: ten parametr określa ContentTransform, które mają mieć zastosowanie, gdy treści zostaną usunięte ze stosu (np. podczas przechodzenia do poprzedniej strony).
  • predictivePopTransitionSpec: ten parametr określa ContentTransform, który ma być stosowany, gdy treści są wyświetlane za pomocą przewidującego gestu cofnięcia.

Zastępowanie przekształceń na poziomie poszczególnych NavEntry

Możesz też zdefiniować niestandardowe animacje dla konkretnych NavEntry, korzystając z ich metadanych. NavDisplay rozpoznaje specjalne klucze metadanych, aby stosować przejścia na podstawie poszczególnych wpisów:

  • NavDisplay.transitionSpec: ta funkcja pomocnicza służy do definiowania animacji nawigacji do przodu.
  • NavDisplay.popTransitionSpec: ta funkcja pomocnicza służy do definiowania animacji przechodzenia do poprzedniego poziomu w przypadku określonego NavEntry.
  • NavDisplay.predictivePopTransitionSpec: ta funkcja pomocnicza służy do definiowania animacji przewidujących gestów wstecz w przypadku określonego NavEntry.

Te przejścia metadanych na poziomie wpisu zastępują globalne przejścia NavDisplay o tej samej nazwie.

Poniższy fragment kodu pokazuje zarówno przejścia globalne NavDisplay, jak i zastąpienie na poziomie poszczególnych 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)
                )
            }
        }
    }
}

Rysunek 1. Aplikacja z animacjami niestandardowymi.