대상 간 애니메이션 처리

NavDisplay는 사용자가 앱을 탐색할 때 원활한 시각적 전환을 만들 수 있는 내장 애니메이션 기능을 제공합니다. 메타데이터를 사용하여 이러한 애니메이션을 NavDisplay에 전역적으로 맞춤설정하거나 NavEntry별로 맞춤설정할 수 있습니다.

기본 전환 재정의

NavDisplayContentTransform를 사용하여 탐색 중에 콘텐츠가 애니메이션되는 방식을 정의합니다. NavDisplay에 전환 매개변수를 제공하여 기본 애니메이션 동작을 재정의할 수 있습니다.

  • transitionSpec: 이 매개변수는 콘텐츠가 백 스택에 추가될 때 (즉, 앞으로 이동할 때) 적용할 ContentTransform를 정의합니다.
  • popTransitionSpec: 이 매개변수는 콘텐츠가 백 스택에서 삭제될 때 (즉, 뒤로 탐색할 때) 적용할 ContentTransform를 정의합니다.
  • predictivePopTransitionSpec: 이 매개변수는 뒤로 탐색 예측 동작을 사용하여 콘텐츠가 팝될 때 적용할 ContentTransform를 정의합니다.

개별 NavEntry 수준에서 전환 재정의

메타데이터를 사용하여 특정 NavEntry의 맞춤 애니메이션을 정의할 수도 있습니다. NavDisplay는 항목별 전환을 적용하는 특수 메타데이터 키를 인식합니다.

  • NavDisplay.transitionSpec: 이 도우미 함수를 사용하여 앞으로 탐색 애니메이션을 정의합니다.
  • NavDisplay.popTransitionSpec: 이 도우미 함수를 사용하여 특정 NavEntry의 뒤로 탐색 애니메이션을 정의합니다.
  • NavDisplay.predictivePopTransitionSpec: 이 도우미 함수를 사용하여 특정 NavEntry의 뒤로 탐색 예측 동작에 대한 애니메이션을 정의합니다.

이러한 항목별 메타데이터 전환은 동일한 이름의 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 = 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)
                )
            }
        }
    }
}

그림 1. 맞춤 애니메이션이 포함된 앱