서버로부터 데이터를 불러오는 과정에서 데이터를 로딩 중인 상태를 사용자에게 보여주기 위해 스켈레톤 로딩 화면을 구현하였는데, 이 부분을 정리해보고자 한다.
LoadingShimmerEffect는 Shimmer 효과를 적용하기 위한 Brush를 생성하고 이를 content에 전달하기 위한 함수이다.
- shimmerColors : 밝은 색상에서 어두운 색상으로 변화하는 애니메이션인 Shimmer 효과를 위한 색상 리스트를 정의한다.
- rememberInfiniteTransition : 무한 반복되는 애니메이션을 기억하기 위해 사용한다.
- animateFloat : 애니메이션을 통해 0 ~ 1000까지의 값을 반복해서 변경한다.
- Brush.linearGradient : Shimmer 효과를 위해 선형 그라데이션 브러시를 생성한다.
@Composable
fun LoadingShimmerEffect(content: @Composable (Brush) -> Unit) {
val shimmerColors = listOf(
Color.LightGray.copy(alpha = 0.6f),
Color.LightGray.copy(alpha = 0.2f),
Color.LightGray.copy(alpha = 0.6f),
)
val transition = rememberInfiniteTransition(label = "")
val translateAnim = transition.animateFloat(
initialValue = 0f,
targetValue = 1000f,
animationSpec = infiniteRepeatable(
animation = tween(
durationMillis = 1000,
easing = FastOutSlowInEasing
),
repeatMode = RepeatMode.Reverse
), label = ""
)
val brush = Brush.linearGradient(
colors = shimmerColors,
start = Offset.Zero,
end = Offset(x = translateAnim.value, y = translateAnim.value)
)
content(brush) // 생성된 브러시를 content 컴포저블에 전달한다.
}
ShimmerGridItem 함수는 Shimmer 효과가 적용될 UI 항목을 정의한다.
실제로 로딩이 완료된 데이터가 표시될 화면과 유사하게 정의하여 로딩 중인 상태와 로딩 완료된 상태를 일관되게 보일 수 있게 한다.
@Composable
internal fun ShimmerGridItem(brush: Brush) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(top = Paddings.xextra),
verticalAlignment = Alignment.CenterVertically
) {
Spacer(
modifier = Modifier
.height(32.dp)
.weight(1f)
.background(brush)
)
Spacer(modifier = Modifier.width(Paddings.xxlarge))
Spacer(
modifier = Modifier
.height(32.dp)
.weight(2f)
.background(brush)
)
}
}
리스트에
LoadingShimmerEffect
와ShimmerGridItem
를 적용하여 각 항목에 Shimmer 효과를 추가한다.
LazyColumn { // 스크롤 가능한 리스트 생성
items(5) { // 리스트에 5개의 항목을 생성
Column { // 세로로 배치
LoadingShimmerEffect { // 각 항목에 Shimmer 효과를 적용
ShimmerGridItem(brush = it) // Shimmer 효가가 적용될 실제 UI 항목을 정의
}
}
}
}