Jetpack Compose에서도 마찬가지로 애니메이션을 구현할 수 있다. 애플리케이션에서 애니메이션을 구현해야하는 이유는 무엇일까?
- 앱의 현재 상황에 관한 시각적인 단서를 준다.
- 앱의 완성도를 높히며, 세련된 느낌을 준다.
- 사용자의 경험을 끌어올려 상호작용을 극대화시킨다.
외에도 우리는 애니메이션을 앱에 구현함으로써 얻는 이점을 위해 애니메이션을 구현하고자 한다.
https://developer.android.com/develop/ui/compose/animation/introduction?hl=ko
위 공식문서에서 설명하길 이렇게 분류를 나눠서 설명하고 있다.
애니메이션 수정자 및 컴포저블
나타남과 사라짐 애니메이션 | 콘텐츠 크기 변경 애니메이션 처리 | 여러 컴포저블 간 애니메이션 |
가치 기반 애니메이션
가치 기반 애니메이션 | 여러 값을 함께 애니메이션 처리 | 무기한으로 속성 애니메이션 처리 |
여기서 우린 애니메이션 수정자 및 컴포저블의 AnimatedVisibility라는 나타남과 사라짐 애니메이션에 대해 알아보고자 한다.
AnimatedVisibility
AnimatedVisibility 컴포저블은 컨텐츠 표시와 사라짐을 애니메이션 처리하는 것이다.
@Composable
fun AnimatedVisibility(
visible: Boolean,
modifier: Modifier = Modifier,
enter: EnterTransition = fadeIn() + expandIn(),
exit: ExitTransition = shrinkOut() + fadeOut(),
label: String = "AnimatedVisibility",
content: @Composable() AnimatedVisibilityScope.() -> Unit
) {
val transition = updateTransition(visible, label)
AnimatedEnterExitImpl(transition, { it }, modifier, enter, exit, content)
}
AnimatedVisibility에는 총 6가지의 파라미터가 들어가는데 이것들은 이와 같은 역할을 맡는다.
- visible - visible 상태(State)가 변화할 때, Animation이 Trigger된다.
- visible이 true일 때, EnterTransition(애니메이션)이 수행되며, visible이 false일 때, ExitTransition이 수행된다.
- modifier - AnimatedVisibility는 애니메이션을 할 Content를 감싸는 레이아웃 역할을 한다. 따라서 modifier = 레이아웃의 modifier다.
- enter - EnterTransition을 인자로 받으며, visible이 false에서 true로 바뀔 때, Trigger되는 애니메이션을 정의한다.
- exit - ExitTransition을 인자로 받으며, visible이 true에서 false로 바뀔 때, Trigger되는 애니메이션을 정의한다.
- label - 이 애니메이션이 무엇을 하는지 설명하기 위한 label 이름표이다.
- content - Animated Visibility를 적용할 Composable Content이다.
var visible by remember {
mutableStateOf(true)
}
// 애니메이션 가시성은 애니메이션이 끝나면 컴포지션에서 항목을 제거한다.
AnimatedVisibility(visible) {
// 추가할 컴포지션
// ...
}
기본적으로 콘텐츠는 페이드 인 및 확장 방식으로 표시되고 페이드 아웃 및 축소 방식으로 사라진다.
EnterTransition 및 ExitTransition을 지정하여 전환을 맞춤 설정할 수 있다는 것이다.
var visible by remember { mutableStateOf(true) }
val density = LocalDensity.current
AnimatedVisibility(
visible = visible,
enter = slideInVertically {
// Slide in from 40 dp from the top.
with(density) { -40.dp.roundToPx() }
} + expandVertically(
// Expand from the top.
expandFrom = Alignment.Top
) + fadeIn(
// Fade in with the initial alpha of 0.3f.
initialAlpha = 0.3f
),
exit = slideOutVertically() + shrinkVertically() + fadeOut()
) {
Text("Hello", Modifier.fillMaxWidth().height(200.dp))
}
위에서도 AnimatedVisibility() 내부에 enter와 exit에 여러 요소를 넣어 맞춤 전환 시키는 것을 알 수 있다.
또한, + 연산자를 사용해 여러 EnterTransition, ExitTransition 객체를 결합하여 각 객체에 선택적 매개변수를 사용해 동작을 맞춤설정 시킨다.
자세한 예시는 다음을 참고하자.
아래는 Jetpack Compose 튜토리얼 - 히어로 목록 앱의 한 부분이다.
@OptIn(ExperimentalAnimationApi::class)
@Composable
fun HeroesList(
heroes: List<Hero>,
modifier: Modifier = Modifier,
contentPadding: PaddingValues = PaddingValues(0.dp)
) {
val visibleState = remember {
MutableTransitionState(false).apply { targetState = true }
}
AnimatedVisibility(
visibleState = visibleState,
enter = fadeIn(animationSpec = spring(dampingRatio = DampingRatioLowBouncy)),
exit = fadeOut(),
modifier = modifier
) {
LazyColumn(contentPadding = contentPadding) {
itemsIndexed(heroes) { index, item ->
HeroesItem(
hero = item,
modifier = Modifier
.padding(vertical = 8.dp, horizontal = 16.dp)
.animateEnterExit(
enter = slideInVertically(
animationSpec = spring(
stiffness = StiffnessVeryLow,
dampingRatio = DampingRatioLowBouncy
),
initialOffsetY = { it * (index + 1) }
)
)
)
}
}
}
}
리스트의 아이템을 나타냄에 있어 AnimatedVisibility()를 사용한다.
MutableTransitionState
val visibleState = remember {
MutableTransitionState(false).apply { targetState = true }
}
위 코드에서 사용된 MutableTransitionState라는 것이 존재한다.
이것을 사용하여 현재 애니메이션의 진행 상태 정보를 관찰시킬 수 있다.
기본적으로 currentState와 targetState를 프로퍼티로 포함하고 있으며, 이 두 값의 초기 상태는 동일하다.
@Composable
fun Test() {
val visibleState = remember {
MutableTransitionState(false).apply { targetState = true }
}
Column {
AnimatedVisibility(
visibleState = visibleState,
) {
Text(text = "Hello, world!")
}
Text(
text = when {
visibleState.isIdle && visibleState.currentState -> "Visible"
!visibleState.isIdle && visibleState.currentState -> "Disappearing"
visibleState.isIdle && !visibleState.currentState -> "Invisible"
else -> "Appearing"
}
)
}
}
위에서 말한 것처럼 visibleState는 AnimatedVisibility의 상태를 관찰하는 데에도 사용할 수 있다.
예를 들어, 위 Test() 컴포저블을 보라.
visibleState.isIdle은 AnimatedVisibility에서 모든 애니메이션이 완료되었는지 여부를 나타내며, visibleState.currentState는 현재 애니메이션의 초기 상태를 반환한다.
위 코드를 실행하면 다음과 같이 나타난다.
Hello, world! Appearing |
→ | Hello, world! Visible |
만약 페이드인 페이드아웃을 넣었다면 상태가 추가적으로 바뀔 것이다.
'개발 > 안드로이드' 카테고리의 다른 글
앱 아키텍처 알아보기 (0) | 2024.05.08 |
---|---|
rememberSaveable이란 (0) | 2024.05.08 |
Scaffold와 LazyColumn (1) | 2024.05.03 |
Jetpack Compose 커스텀 그림자 (0) | 2024.05.02 |
Jetpack Compose에서의 State (0) | 2024.04.30 |
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!