“Android 로봇은 Google에서 제작하여 공유한 저작물을 복제하거나 수정한 것으로 Creative Commons 3.0 저작자 표시 라이선스의 약관에 따라 사용되었습니다.”
Compose에서 각 Screen(Compsoable)이 전환될 때 Transition을 설정하고 싶을 때가 있다. Navigation을 사용 중이라면 NavHost
에서 손쉽게 설정이 가능하다.
아래의 예제소스는 MainScreen을 시작으로
FirstScreen, SecondScreen으로 전환하는 소스이다.
@Composable
fun AppNavHost(
navHostController: NavHostController,
paddingValues: PaddingValues,
viewModel: MainViewModel,
stateViewModel: StateViewModel
) {
NavHost(
navController = navHostController,
startDestination = Screen.Main.route,
enterTransition = {
slideIntoContainer(
AnimatedContentTransitionScope.SlideDirection.Left,
animationSpec = tween(300)
)
},
exitTransition = {
slideOutOfContainer(
AnimatedContentTransitionScope.SlideDirection.Left,
animationSpec = tween(300)
)
},
popEnterTransition = {
slideIntoContainer(
AnimatedContentTransitionScope.SlideDirection.Right,
animationSpec = tween(300)
)
},
popExitTransition = {
slideOutOfContainer(
AnimatedContentTransitionScope.SlideDirection.Right,
animationSpec = tween(300)
)
}
) {
composable(Screen.Main.route) {
MainScreen(navHostController)
}
composable(Screen.First.route) {
FirstScreen(viewModel, stateViewModel)
}
composable(Screen.Second.route) {
SecondScreen(viewModel, stateViewModel)
}
}
}
예를 들어 위와 같은 소스가 있다고 가정해보면
NavHost
의 파라미터를 지정하는 것으로 간단하게 Transition을 설정할 수 있다.
각 파라미터의 개념을 MainScreen에서 FirstScreen으로 전환된다는 가정 하에 아래와 같이 설명할 수 있다.
enterTransition
FirstScreen으로 진입 시 애니메이션exitTransition
FirstScreen으로 진입할 때 MainScreen의 애니메이션popEnterTransition
뒤로가기 시 MainScreen의 애니메이션popExitTransition
뒤로가기 시 FirstScreen의 애니메이션
slideIntoContainer
다음 Screen 진입 시 사용될 slide 애니메이션 객체,EnterTransition
을 반환한다.slideOutOfcontainer
이전 Screen으로 돌아갈 때 사용될 slide 애니메이션 객체,ExitTransition
을 반환한다.
NavHost
가 아닌 composable
에서 설정도 가능하다.
모든 Screen에 각 각 다른 transition을 설정하고 싶은 경우에 해당한다.
NavHost
와 마찬가지로 파라미터로 설정할 수 있다.
composable(
route = Screen.First.route,
enterTransition = {
slideIntoContainer(
AnimatedContentTransitionScope.SlideDirection.Left,
animationSpec = tween(300)
)
},
exitTransition = {
slideOutOfContainer(
AnimatedContentTransitionScope.SlideDirection.Left,
animationSpec = tween(300)
)
},
popEnterTransition = {
slideIntoContainer(
AnimatedContentTransitionScope.SlideDirection.Right,
animationSpec = tween(300)
)
},
popExitTransition = {
slideOutOfContainer(
AnimatedContentTransitionScope.SlideDirection.Right,
animationSpec = tween(300)
)
}
) {
FirstScreen(viewModel, stateViewModel)
}
NavHost
예제와 마찬가지로 MainScreen, FirstScreen, SecondScreen이 있다고 가정해보자,
위 예제소스대로 작동해보면 FirstScreen의 transition만 적용되는 것을 확인할 수 있다
모든 Screen에 transition을 적용하고 특정 Screen만 transition을 다르게 하고 싶을 수도 있다.
이럴 때 NavHost
에 transition을 지정 후 특정 Screen composable에만 transition을 다르게 적용하면 되나 싶지만
이럴 경우 transition이 중복되어 의도한 바와 전혀 다른 결과물이 나온다.
이때에는 NavHost
의 transition 파라미터 분기에서 현재 route를 기준으로 분기문을 작성하여 처리하면 된다.
아래 예제를 살펴보지
@Composable
fun AppNavHost(
navHostController: NavHostController,
paddingValues: PaddingValues,
viewModel: MainViewModel,
stateViewModel: StateViewModel
) {
NavHost(
navController = navHostController,
startDestination = Screen.Main.route,
enterTransition = {
when(targetState.destination.route) {
Screen.First.route -> EnterTransition.None
Screen.Second.route -> {
fadeIn(animationSpec = tween(300))
}
else -> {
slideIntoContainer(
AnimatedContentTransitionScope.SlideDirection.Left,
animationSpec = tween(300)
)
}
}
},
exitTransition = {
when(targetState.destination.route) {
Screen.First.route -> ExitTransition.None
Screen.Second.route -> {
fadeOut(animationSpec = tween(300))
}
else -> {
slideOutOfContainer(
AnimatedContentTransitionScope.SlideDirection.Left,
animationSpec = tween(300)
)
}
}
},
popEnterTransition = {
when(targetState.destination.route) {
Screen.First.route -> EnterTransition.None
Screen.Second.route -> {
fadeIn(animationSpec = tween(300))
}
else -> {
slideIntoContainer(
AnimatedContentTransitionScope.SlideDirection.Right,
animationSpec = tween(300)
)
}
}
},
popExitTransition = {
when(targetState.destination.route) {
Screen.First.route -> ExitTransition.None
Screen.Second.route -> {
fadeOut(animationSpec = tween(300))
}
else -> {
slideOutOfContainer(
AnimatedContentTransitionScope.SlideDirection.Right,
animationSpec = tween(300)
)
}
}
}
) {
composable(Screen.Main.route) {
MainScreen(navHostController)
}
composable(Screen.First.route) {
FirstScreen(viewModel, stateViewModel)
}
composable(Screen.Second.route) {
SecondScreen(viewModel, stateViewModel)
}
}
}
분기문을 살펴보면 targetState
는 이동(전환)하려는 Screen의 BackStackEntry
으로 route를 이용한 분기처리가 가능하다.
추가적으로 transitoin 애니메이션은 slide, fade, scale 등 다양한 방법을 지원하며 이 부분에 대해서는 추후 다시 포스팅을 작성해보도록 하겠다.
개인적으로 공부했던 것을 바탕으로 작성하다보니
잘못된 정보가 있을수도 있습니다.
인지하게 되면 추후 수정하겠습니다.
피드백은 언제나 환영합니다.
읽어주셔서 감사합니다.