컴포즈에서 여러 방법으로 UI에 애니메이션을 적용할 수 있다. 간단한 애니메이션을 위한 고수준의 API 부터 전체를 제어하고 복잡한 트렌지션을 위한 저수준의 API까지 있다. 자세한 내용은 문서를 참조하자.

애니메이션을 구현하기 위해 animateDpAsState라는 컴포저블 함수를 사용해볼 것이다. 이 함수는 애니메이션이 끝날 때까지 값이 지속적으로 갱신되는 State 객체를 반환한다. 이 함수는 타입이 Dp인 타겟값을 매개변수로 갖는다.

애니메이션에 사용할 extraPadding을 생성하여 확장된 상태(expanded)에 의존하도록 하자. 또한 by 키워드와 함께 property delegate를 사용하자.

@Composable
private fun Greeting(name: String) {

    var expanded by remember { mutableStateOf(false) }

    val extraPadding by animateDpAsState(
        if (expanded) 48.dp else 0.dp
    )
    Surface(
        color = MaterialTheme.colors.primary,
        modifier = Modifier.padding(vertical = 4.dp, horizontal = 8.dp)
    ) {
        Row(modifier = Modifier.padding(24.dp)) {
            Column(modifier = Modifier
                .weight(1f)
                .padding(bottom = extraPadding)
            ) {
                Text(text = "Hello, ")
                Text(text = name)
            }
            OutlinedButton(
                onClick = { expanded = !expanded }
            ) {
                Text(if (expanded) "Show less" else "Show more")
            }

        }
    }
}

앱을 실행하고 애니메이션을 확인해보자.

Note: 만약 첫번째 아이템 하나를 클릭해서 확장한 다음, 첫번째 아이템이 안보이도록 20번째쯤으로 스크롤했다가 다시 첫번째 아이템으로 돌아가면 다시 원래의 사이즈로 돌아온 것을 확인할 수 있다. 만약 확장 상태를 유지하고 싶다면 rememberSaveable 을 사용할 수 있다.

animateDpAsState 함수는 선택적으로 animationSpec이라는 파라미터를 취한다. animationSpec은 애니메이션을 커스텀 할 수 있도록 도와준다. 통통 튀는 애니메이션을 추가적으로 적용해보자.

@Composable
private fun Greeting(name: String) {

    var expanded by remember { mutableStateOf(false) }

    val extraPadding by animateDpAsState(
        if (expanded) 48.dp else 0.dp,
        animationSpec = spring(
            dampingRatio = Spring.DampingRatioMediumBouncy,
            stiffness = Spring.StiffnessLow
        )
    )

    Surface(
    ...
            Column(modifier = Modifier
                .weight(1f)
                .padding(bottom = extraPadding.coerceAtLeast(0.dp))

    ...

    )
}

padding은 절대로 음수가 될 수 없는 점을 명심하자. 음수로 지정하면 크래시가 발생한다. 이런 점 때문에 미묘한 애니메이션 버그가 발생할 수 있는데, 이 부분은 마무리 작업 편에서 수정하기로 하자.

spring spec은 시간과 관련된 어떠한 매개변수도 취하지 않는다. 대신에 물리적인 속성(감폭 및 단단함)에 의존하여 애니메이션을 좀더 자연스럽게 만든다. 앱을 실행하여 새롭게 적용된 애니메이션을 살펴보자.

animate*AsState으로 생성한 어떤 애니메이션이든 중단이 가능하다. 이는 만약 타겟값이 애니메이션 중간에 변경되면, animate*AsState가 애니메이션을 재시작 하고 새로운 값을 가르키는 것을 의미한다. 통통튀는 애니메이션의 중단은 특별히 자연스러워 보인다.

다른 타입의 애니메이션을 살펴보고 싶다면 spring에 다른 매개변수를 적용하거나 tween 이나 repeatable을 spec을 사용하고 animateColorAsState와 같은 다른 함수를 사용해보자. 또는 애니메이션 문서를 참고하여 다른 애니메이션을 적용해보자.

카테고리: Compose

0개의 댓글

답글 남기기

Avatar placeholder

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.