I am trying to implement a scroll indicator on LazyRow. Ideally it would transition smoothly while scrolling, but I read that it is not possible because we only have access to the firstVisibleItemIndex
from state. But even then, I have not been able to implement it the way I want because my items only take 90% of the width of the screen, therefore a little bit of the item before is shown. When the second item is selected, the first one is still visible on the screen, so firstVisibleItemIndex
never really changes until you scroll a bit past it.
Is there a way to smoothly get the scrollable percentage? If not, how can I fix my case, accounting for the items not taking total width of parent:
This is what I have so far. Code adapted to hide sensitive info, but this should run:
@OptIn(ExperimentalFoundationApi::class)
@Composable
private fun SnappingRowWithIndicator(items: List<Int>) {
val state = rememberLazyListState()
val firstVisibleItemIndex = state.firstVisibleItemIndex
val percent = (firstVisibleItemIndex / (items.size).toFloat()) * 100f
LaunchedEffect(percent) {
val scrollText = "scroll: $percent"
println(scrollText)
}
LazyRow(
horizontalArrangement = Arrangement.spacedBy(16.dp),
state = state,
flingBehavior = rememberSnapFlingBehavior(lazyListState = state)
) {
items(items) { dto ->
Text(
modifier = Modifier
.height(32.dp)
.fillParentMaxWidth(0.9f)
.background(Color.White)
.padding(vertical = 8.dp),
color = Color.Black,
text = dto.toString(),
textAlign = TextAlign.Center
)
}
}
Row(
modifier = Modifier
.fillMaxWidth()
.padding(top = 8.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp, alignment = Alignment.CenterHorizontally)
) {
items.forEachIndexed { index, _ ->
// todo color and not color the dots according to the index and the percentage scrolled
Box(modifier = Modifier
.size(8.dp)
.background(color = DesignSystem.Color.white, shape = CircleShape))
}
}
}
How it looks with the second item selected: