본문 바로가기
안드로이드 공부 노트/Compose(컴포즈)

[Android-Compose] 안드로이드 컴포즈 애니메이션 예제와 함께 알아보기!(animateColorAsState, AnimatedVisibility, fadeIn, fadeOut )

by 지게요 2024. 1. 12.
728x90
반응형

이번 공부 포스팅은 컴포즈 애니메이션에 대해 간단하게 알아보겠다.

# animateColorAsState

                     

우선 이 컴포저블 함수는 이름에서도 알 수 있다시피 Color에 관련한 애니메이션 함수이다.

인자로는 targetValue, animationSpec, label, finishedListener 4가지가 들어가야 한다.

그중 우리가 여기서 볼 거는 targetValue이다 이 인자에는 바꾸고 싶은 색상을 넣으면 된다.

나머지 인자들은 옵션이기 때문에 더 자세히 알고 싶으시면 따로 검색을 하는 걸 추천한다.

 

반환은 State <Color>로 되기 때문에 by를 통해 값을 받아오는 게 깔끔하고 좋다

 

아래는 animateColorAsState의 유무의 차이이다.

사람에 따라서는 차이가 없다고 느낄 수도 있지만 작은 디테일의 변화가 사용자의 사용성을 크게 향상할 수 있다고 생각한다. 그래서 이러한 색상을 변경할 때 animateColorAsState를 사용하는 걸 추천한다.

- Before After 미리 보기

   <Before>                                                                                             <After>

 


## animateColorAsState 사용법

이제 사용법을 한번 알아보자

사용법은 위에서 설명한 인자 중 targetValue만 사용한다면 간단하다!

 

우선 아래코드는 animateColorAsState 사용하기 전 코드이다.

Button클릭 시 isChange라는 변수를 이용해 imageColor를 바꿔주고 있다.

 

<animateColorAsState 사용 전>

var isChange by remember { mutableStateOf(false) }
val imageColor = if (isChange) Blue else Red

    Column(
        modifier = Modifier.fillMaxSize()
    ) {
        Row(
            modifier = Modifier
                .fillMaxWidth()
                .padding(top = 25.dp),
            horizontalArrangement = Arrangement.SpaceAround
        ) {
            Button(
                modifier = Modifier.align(Alignment.CenterVertically),
                onClick = { isChange = !isChange }
            ) {
                Text(
                    text = "컬러 변경",
                    fontSize = 17.sp
                )
            }
            Box(
                modifier = Modifier
                    .size(128.dp)
                    .background(imageColor)
            )
        }
    }

 

아래 코드는 animateColorAsState 사용 후 코드이다.

주석 처리된 곳을 보면 어떤 부분이 바뀐 건지 설명을 적어놨다.

간단하게 설명하면 변경하고 싶은 Color 밖에다가 animateColorAsState를 한번 감싸주면 된다!

 

< animateColorAsState 사용 후 >

var isChange by remember { mutableStateOf(false) }

// animateColorAsState로 감싸 주고 by를 이용해서 받아온다
val imageColor by animateColorAsState(if (isChange) Blue else Red)

  Column(
            modifier = Modifier.fillMaxSize()
        ) {
            Row(
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(top = 25.dp),
                horizontalArrangement = Arrangement.SpaceAround
            ) {
                Button(
                    modifier = Modifier.align(Alignment.CenterVertically),
                    onClick = { isChange = !isChange }
                ) {
                    Text(
                        text = "컬러 변경",
                        fontSize = 17.sp
                    )
                }
                Box(
                    modifier = Modifier
                        .size(128.dp)
                        .background(imageColor)
                )
           }
       }

 


# AnimatedVisibility

 

해당 컴포저블 함수는 Visibility 가시성 즉 표시와 사라짐 애니메이션을 처리할 때 필요한 함수이다.

필요한 인자는 6가지가 있는데 visible과 content만 필수적으로 넣어줘야 한다.

 

< visible 인자 설명>

visible : 상태(State)가 변화할 때 Animation이 Trigger된다. visible 이 true일 때는 EnterTransition(애니메이션)이 수행되며, visible이 false일 때는 ExitTransition이 수행된다. 

 

또한 Row, Column에 따라 기본값이 다르다 자세한 건 아래 Before After 미리 보기를 통해 보면 이해할 것이다.

 

이번에도 아래는 AnimatedVisibility의 유무의 차이이다.

animateColorAsState와는 다르게 확실히 표시되고 사라질 때 많은 변화가 있다.

- Before After 미리 보기보기

   <Before>                                                                                                        <After>


## AnimatedVisibility 사용법

AnimatedVisibility에서 visible만 넣어줬을 때 나타나는 애니메이션 값을 표로 정리해 봤다.

기본 값 Row Column
표시 왼쪽 -> 오른쪽 위 -> 아래
사라질때 오른쪽 -> 왼쪽 아래 -> 위

 

우선 가장 기본적인 사용법을 코드를 통해 알아보겠다.

이 예제에서는 Row만 다뤄보도록 하겠다.

 

여기도 마찬가지로 Button클릭 시 isVisible라는 변수를 이용해 표시 유무를 바꿔주고 있다.

AnimatedVisibility 사용 전에는 if문으로 단순 표시 제어를 해주고 있다.

 

<AnimatedVisibility 사용 전>

var isVisible by remember { mutableStateOf(false) }

Column(
    modifier = Modifier
        .fillMaxWidth()
        .height(150.dp)
        .border(1.dp, Color.Blue)
        .padding(top = 20.dp)
) {
    Text(
        modifier = Modifier
            .fillMaxWidth()
            .padding(top = 10.dp)
            .align(Alignment.CenterHorizontally),
        text = "Row의 AnimatedVisibility",
        fontSize = 17.sp,
        textAlign = TextAlign.Center
    )
    Row(
        modifier = Modifier
            .fillMaxWidth()
            .padding(vertical = 25.dp),
    ) {
        Button(
            modifier = Modifier
                .padding(horizontal = 40.dp),
            onClick = { isVisible = !isVisible }
        ) {
            Text(
                text = if (isVisible) "HIDE" else "SHOW",
                fontSize = 17.sp
            )
        }
        if(isVisible) {
            Box(
                modifier = Modifier
                    .size(128.dp)
                    .background(Color.Blue)
            )
        }
    }
}

 

<AnimatedVisibility 사용 후>

var isVisible by remember { mutableStateOf(false) }

Column(
    modifier = Modifier
        .fillMaxWidth()
        .height(150.dp)
        .border(1.dp, Color.Blue)
        .padding(top = 20.dp)
) {
    Text(
        modifier = Modifier
            .fillMaxWidth()
            .padding(top = 10.dp)
            .align(Alignment.CenterHorizontally),
        text = "Row의 AnimatedVisibility",
        fontSize = 17.sp,
        textAlign = TextAlign.Center
    )
    Row(
        modifier = Modifier
            .fillMaxWidth()
            .padding(vertical = 25.dp),
    ) {
        Button(
            modifier = Modifier
                .padding(horizontal = 40.dp),
            onClick = { isVisible = !isVisible }
        ) {
            Text(
                text = if (isVisible) "HIDE" else "SHOW",
                fontSize = 17.sp
            )
        }
        // AnimatedVisibility 안에 visible를 isVisible로 지정
        // 이외 아무것도 안 정해주면 기본 애니메이션 적용
        AnimatedVisibility(visible = isVisible) {
            Box(
                modifier = Modifier
                    .size(128.dp)
                    .background(Color.Blue)
            )
        }
    }
}

 

AnimatedVisibility 사용 후에는 visible 인자에 표시 유무를 바꿔주고 있는 isVisible를 넣어준다

그리고 AnimatedVisibility 스코프 안에 표시해주고 싶은 콘텐츠를 작성해 주면 끝이다.

 

번외로 AnimatedVisibility안 속성 EnterTransition, ExitTransition 이 두 개를 이용해서 다양한 애니메이션을 처리할 수 있다.

이것도 구글에서 편하게 이미 확장 함수로 만들어 놨으니 자세한 건 공식 문서를 보고 적용하면 된다.

아래는 공식 문서에 있는 확장 함수로 만들어진 애니메이션 미리 보기이다!

 

## 기본 확장 함수 사용방법

예를 들어 콘텐츠가 왼쪽에서 오른쪽으로 나오게 하고 싶고 오른쪽에서 왼쪽으로 들어가게 하고 싶은 경우

이경우는 위에서 확장함수 미리 보기에서 보다시피 expandHorizontally / shrinkHorizontally를 사용해 주면 간단하다.

enter 속성에 경우 보일 때 실행되니 expandHorizontally() 넣어주고 exit 속성에는 사라질 때 실행되니 shrinkHorizontally()를 아래처럼 넣어주면 끝이다!

/** enter = expandHorizontally() exit = shrinkHorizontally() 적용 **/
            AnimatedVisibility(
                visible = isVisible,
                enter = expandHorizontally(),
                exit = shrinkHorizontally()
            ) {
                Box(
                    modifier = Modifier
                        .size(128.dp)
                        .padding(top = 20.dp)
                        .background(Color.Blue)
                )
            }

 

## + 연산자를 통해 애니메이션 객체 결합

기존 구현 방법 : 콘텐츠가 왼쪽에서 오른쪽으로 나오게 하고 싶고 오른쪽에서 왼쪽으로 들어가게 하고 싶은 경우

새롭게 기획된 방법 : 콘텐츠가 왼쪽에서 오른쪽으로 나올 때 서서히 나타나는 효과가 있으면 좋겠고 오른쪽에서 왼쪽으로 사라질 때 서서히 사라졌으면 좋겠는 경우

위와 같이 요구하는 애니메이션 스펙이 하나가 늘어났을 때 해결방법은 있다.

애니메이션 객체는 + 연산자를 통해 결합이 가능하다는 특징이 있다.

 /** + 연산자를 이용해 애니메이션 추가 **/
            AnimatedVisibility(
                visible = isVisible,
                enter = expandHorizontally() + fadeIn(),
                exit = shrinkHorizontally() + fadeOut(),
            ) {
                Box(
                    modifier = Modifier
                        .size(128.dp)
                        .padding(top = 20.dp)
                        .background(Color.Blue)
                )
            }

위처럼 간단하게 + 만 붙여주면 결합은 끝이 난다.

 

 

잘 보면 아래쪽은 Horizontally특성도 갖고 있고 fade 특성도 갖고 있다!

 

이외에도 애니메이션을 활용하면 방법은 너무 다양하고 애니메이션에 관련된 함수들도 엄청 많다!

틈틈이 사용해 보고 공식문서를 통해 공부해야 할 거 같다.

 

전체코드 GitHub

https://github.com/JiSeokYeom/BlogComposeEx_2

 

GitHub - JiSeokYeom/BlogComposeEx_2

Contribute to JiSeokYeom/BlogComposeEx_2 development by creating an account on GitHub.

github.com

 

반응형