Jetpack Compose의 시각적 애니메이션
Jetpack Compose의 시각적 애니메이션
Jetpack Compose는 UI 상태 간 부드러운 전환을 구현할 수 있는 선언적(declarative) 애니메이션 시스템을 제공합니다. 내장 API를 활용하면 컴포저블(composable)의 등장과 퇴장, 콘텐츠 변경, 크기 조절, 프로퍼티 전환 등 다양한 애니메이션을 손쉽게 구현할 수 있습니다. 이러한 애니메이션은 최적의 성능을 유지하면서 사용자 경험을 크게 높여 줍니다. 특히, 기존의 명령형(imperative) 뷰 시스템에서는 ObjectAnimator나 ValueAnimator를 직접 관리해야 했지만, Compose에서는 상태(state) 변경만으로 애니메이션이 자동으로 동작하기 때문에 훨씬 간결하고 직관적인 코드를 작성할 수 있습니다.
이번 면접 질문을 통하여 아래 내용들을 학습하실 수 있습니다.
AnimatedVisibility를 사용하여 컴포저블의 등장 및 퇴장 애니메이션을 구현할 수 있습니다.Crossfade를 활용하여 서로 다른 UI 상태 간 부드러운 전환을 적용할 수 있습니다.AnimatedContent로 동적 콘텐츠 업데이트에 애니메이션을 적용할 수 있습니다.animate*AsState함수 계열을 사용하여 프로퍼티 기반 애니메이션을 구현할 수 있습니다.animateContentSize를 활용하여 자동 크기 변경 애니메이션을 처리할 수 있습니다.
AnimatedVisibility를 활용한 등장과 퇴장 애니메이션
AnimatedVisibility는 컴포저블의 등장(enter) 및 퇴장(exit) 전환을 애니메이션으로 처리합니다. 기본적으로 등장 시에는 페이드 인(fade in)과 확장(expand) 효과를 적용하고, 퇴장 시에는 페이드 아웃(fade out)과 축소(shrink) 효과를 적용합니다. EnterTransition과 ExitTransition을 활용하면 커스텀 전환 효과를 직접 정의할 수도 있습니다.
@Composable
fun AnimatedVisibilityExample() {
var isVisible by remember { mutableStateOf(true) }
Column {
Button(onClick = { isVisible = !isVisible }) {
Text("Toggle Visibility")
}
AnimatedVisibility(
visible = isVisible,
enter = fadeIn() + expandVertically(),
exit = fadeOut() + shrinkVertically()
) {
Box(
modifier = Modifier
.size(100.dp)
.background(Color.Blue)
)
}
}
}
위의 코드에서 Box는 등장 시 페이드 인과 함께 수직으로 확장되고, 퇴장 시 페이드 아웃과 함께 수직으로 축소됩니다. + 연산자를 사용하면 여러 전환 효과를 하나의 복합 애니메이션으로 결합할 수 있습니다. 가령, fadeIn() + slideInHorizontally()처럼 조합하면 페이드 인과 수평 슬라이드 효과를 동시에 적용할 수 있어, 실무에서 다양한 UX 요구 사항에 유연하게 대응할 수 있습니다.
Crossfade를 활용한 상태 전환
Crossfade는 페이드 효과를 사용하여 두 컴포저블 간의 전환을 애니메이션으로 처리합니다. 탭 내비게이션이나 화면 전환, 컴포넌트 전환에 적합합니다.
@Composable
fun CrossfadeExample() {
var selectedScreen by remember { mutableStateOf("Home") }
Column {
Row {
Button(onClick = { selectedScreen = "Home" }) {
Text("Home")
}
Button(onClick = { selectedScreen = "Profile" }) {
Text("Profile")
}
}
Crossfade(targetState = selectedScreen) { screen ->
when (screen) {
"Home" -> Text("Home Screen", fontSize = 24.sp)
"Profile" -> Text("Profile Screen", fontSize = 24.sp)
}
}
}
}