이번 공부 포스팅은 컴포즈 애니메이션에 대해 간단하게 알아보겠다.
# 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