

인스타 스토리를 보면 위에 바느질처럼 되어있는 page indicator를 본 적이 있을 것이다. 오늘은 이 page indicator를 만들어 볼 것이다.
val dotHeight = 4.dp
Row(
modifier = modifier
.fillMaxWidth()
.wrapContentHeight(),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(4.dp)
) {
repeat(pageCount) { index ->
Box(
modifier = Modifier
.height(dotHeight)
.weight(1f)
.background(
color = if (index < currentPage) {
Color.White.copy(alpha = 0.8f)
} else {
Color.White.copy(alpha = 0.4f)
},
shape = RoundedCornerShape(16.dp)
)
)
}
}
Row를 통해서 pageCount만큼 일정 크기로 Box를 그려주고 currentPage에 따라서 alpha값으로 몇 페이지까지 봤는지 표시해주었다.
현재 페이지는 일정 시간동안 page가 보여지고 나면 다음 페이지로 자동으로 넘어간다. 현재 페이지가 보여지는 시간이 몇 초 남았는지 보여주는 애니메이션을 currentPage Box에 추가로 설정해주었다.
val scaleAnimatable = remember(currentPage) { Animatable(0f) }
LaunchedEffect(currentPage) {
scaleAnimatable.animateTo(
targetValue = 1f,
animationSpec = tween(
durationMillis = pageDuration,
easing = LinearEasing
)
)
if (scaleAnimatable.value == 1f) {
onPageAnimationEnded()
}
}
repeat(pageCount) { index ->
Box(
modifier = Modifier
.height(dotHeight)
.weight(1f)
.background(
if (index < currentPage) {
Color.White.copy(alpha = 0.8f)
} else {
Color.White.copy(alpha = 0.4f)
},
shape = RoundedCornerShape(16.dp)
)
) {
if (index == currentPage) {
Box(
modifier = Modifier
.height(dotHeight)
.fillMaxWidth()
.graphicsLayer {
scaleX = scale.value
transformOrigin = TransformOrigin(0f, 0.5f)
}
.background(
Color.White.copy(alpha = 0.8f)
)
)
}
}
}
scale을 통해서 애니메이션을 설정해주었고 transforOrigin을 변경해서 왼쪽부터 사이즈가 커지도록 설정해주었다.
그리고 animation이 끝나면 onPageAnimationEnded()를 통해서 다음 데이터로 넘어갈 수 있도록 알려주었다.
그럼 이렇게 만들어진다!