본문 바로가기
개발/안드로이드

Android Compose Scroll Indicator 그리기

by EPdev 2024. 8. 1.
728x90

Android 앱 개발을 Compose 로 구현하는데, 디자이너분께서 아래와 같은 Scroll Indicator 를 그려달라고 한다. (구현 예제화면)

 

스크롤의 움직임이 개발 마감기한과 완성도 사이에서 왔다갔다하는 내 신세를 보여주는 것 같아서 한번 구현해보기로 한다...ㅠ

 

개념부터 보자면

1. 리스트의 전체 카운트가 스크롤할 수 있는 최대 길이가 된다.

2. 현재 화면에 노출되는 마지막 아이템의 index가 현재 스크롤의 위치가 된다. 위와 같은 스크롤에서는 현재 스크롤이 몇 % 되었냐를 구하는 것이기 때문에 (현재 index / total count) 로 계산하였는데, 다른 스크롤처럼 보여줄 필요가 있을 때 이 부분을 응용해서 사용할 수 있겠다.

3. 스크롤 할 때, 현재 보이는 마지막 아이템의 index가 변화하는데 이걸 animation으로 나타내준다.

 

코드는 그렇게 어렵지 않다.

import androidx.compose.animation.core.animateDpAsState
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
@Composable
fun HorizontalSmallScrollIndicator(
modifier: Modifier = Modifier,
lazyRowState: LazyListState
) {
val layoutInfo =
remember { derivedStateOf { lazyRowState.layoutInfo } }
val totalItems = layoutInfo.value.totalItemsCount
val lastVisibleItemIndex =
layoutInfo.value.visibleItemsInfo.lastOrNull()?.index ?: 0
val scrollFraction =
(lastVisibleItemIndex + 1).toFloat() / totalItems
val animatedWidth by animateDpAsState(
targetValue = 80.dp * scrollFraction,
label = "scrollIndicator"
)
Box(
modifier = modifier.fillMaxWidth(),
contentAlignment = Alignment.Center
) {
Box(
modifier = modifier
.width(80.dp)
.height(2.dp)
.clip(shape = RoundedCornerShape(16.dp))
.background(Color.LightGray)
) {
Box(
modifier = modifier
.height(2.dp)
.width(animatedWidth)
.clip(shape = RoundedCornerShape(16.dp))
.background(Color.DarkGray)
)
}
}
}

간단하게 스크롤 인디케이터를 만들어봤다.

인디케이터의 크기나 작동 메커니즘 같은건 이 개념에서 응용해서 작성할 수 있을 것 같다.

마감기한을 잘 준수하면서 요구사항도 만족시켜서 다행이다!

 

끝!

728x90

댓글