Анимация между пунктами назначения

NavDisplay предоставляет встроенные возможности анимации для создания плавных визуальных переходов по мере перемещения пользователей по вашему приложению. Вы можете настроить эти анимации глобально для NavDisplay или на уровне Scene с помощью метаданных.

Разберитесь во встроенных возможностях анимации.

NavDisplay использует API ContentTransform для определения того, как анимируется контент во время навигации. NavDisplay автоматически анимирует переходы между сценами, когда изменяется ключ, производный от класса текущей сцены и ее свойства key . При изменении этого ключа NavDisplay использует ContentTransform для типа перехода — вперед, назад или предиктивный возврат — из соответствующей сцены в переходе. Если ContentTransform не определен, NavDisplay возвращается к использованию соответствующего перехода по умолчанию .

Переопределить переходы по умолчанию

Вы можете переопределить поведение анимации по умолчанию, указав параметры перехода в NavDisplay .

  • transitionSpec : Этот параметр определяет ContentTransform , применяемый при добавлении контента в стек возврата (т. е. при переходе вперед).
  • popTransitionSpec : Этот параметр определяет ContentTransform , применяемый при удалении контента из стека "Назад" (т.е. при переходе назад).
  • predictivePopTransitionSpec : Этот параметр определяет ContentTransform , применяемый при удалении контента с помощью предиктивного жеста "назад".

Переопределение переходов на уровне Scene

Вы можете использовать метаданные для определения пользовательских анимаций для отдельных сцен, используя следующие ключи метаданных, определенные NavDisplay :

Если эти переходы на уровне сцены заданы, они используются вместо соответствующих настроек по умолчанию, установленных в 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)
                )
            }
        }
    }
}

Рисунок 1. Приложение с пользовательскими анимациями.

Переходы между сценами через элементы навигации.

В приложениях, создающих пользовательские макеты с использованием сцен , возможно включение элемента NavEntry в свойство entries обеих сцен во время перехода. Внутри NavDisplay проверяет, отображается ли каждый элемент не более чем в одной сцене одновременно, что может привести к резким переходам при изменении сцены, отображающей NavEntry . Для плавной анимации элементов между сценами можно обернуть NavDisplay в SharedTransitionLayout и передать SharedTransitionScope элементу NavDisplay , как показано в следующем примере:

SharedTransitionLayout {
    NavDisplay(
        // ...
        sharedTransitionScope = this
    )
}