면접 질문실전 질문꼬리 질문

Jetpack Compose의 시각적 애니메이션

skydovesJaewoong Eum (skydoves)||7분 소요

Jetpack Compose의 시각적 애니메이션

Jetpack Compose는 UI 상태 간 부드러운 전환을 구현할 수 있는 선언적(declarative) 애니메이션 시스템을 제공합니다. 내장 API를 활용하면 컴포저블(composable)의 등장과 퇴장, 콘텐츠 변경, 크기 조절, 프로퍼티 전환 등 다양한 애니메이션을 손쉽게 구현할 수 있습니다. 이러한 애니메이션은 최적의 성능을 유지하면서 사용자 경험을 크게 높여 줍니다. 특히, 기존의 명령형(imperative) 뷰 시스템에서는 ObjectAnimatorValueAnimator를 직접 관리해야 했지만, Compose에서는 상태(state) 변경만으로 애니메이션이 자동으로 동작하기 때문에 훨씬 간결하고 직관적인 코드를 작성할 수 있습니다.

이번 면접 질문을 통하여 아래 내용들을 학습하실 수 있습니다.

  • AnimatedVisibility를 사용하여 컴포저블의 등장 및 퇴장 애니메이션을 구현할 수 있습니다.
  • Crossfade를 활용하여 서로 다른 UI 상태 간 부드러운 전환을 적용할 수 있습니다.
  • AnimatedContent로 동적 콘텐츠 업데이트에 애니메이션을 적용할 수 있습니다.
  • animate*AsState 함수 계열을 사용하여 프로퍼티 기반 애니메이션을 구현할 수 있습니다.
  • animateContentSize를 활용하여 자동 크기 변경 애니메이션을 처리할 수 있습니다.

AnimatedVisibility를 활용한 등장과 퇴장 애니메이션

AnimatedVisibility는 컴포저블의 등장(enter) 및 퇴장(exit) 전환을 애니메이션으로 처리합니다. 기본적으로 등장 시에는 페이드 인(fade in)과 확장(expand) 효과를 적용하고, 퇴장 시에는 페이드 아웃(fade out)과 축소(shrink) 효과를 적용합니다. EnterTransitionExitTransition을 활용하면 커스텀 전환 효과를 직접 정의할 수도 있습니다.

@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)
            }
        }
    }
}

이 면접 질문은 구독자 전용입니다

Dove Letter를 구독하시면 안드로이드, 코틀린 개발 관련 독점 면접 질문의 전체 내용을 볼 수 있습니다.

구독하기