I have a lazy row that contains items. Now I want to make an API call for the items which are fully visible in the viewport whenever the user scrolls the lazy row.
I have tried the following code:
listState = rememberLazyListState()
LaunchedEffect(listState){
snapshotFlow { listState.firstVisibleItemIndex }
.collectLatest{
Log.d("printed Item", listState.firstVisibleItemIndex.toString())
}}
The problems with this code are:
When the first item is partially visible and 2nd item is fully visible [1]: https://i.sstatic.net/l5QcB.jpg
When the 2nd tile is fully visible and the first tile is completely invisible [2]: https://i.sstatic.net/6rmiQ.jpg
For the tablets where 2 items are completely visible [3]: https://i.sstatic.net/QYRTI.jpg
Can anyone please tell me how to resolve my issue?
All info about visible items is available in state.layoutInfo
. To check wether the item is visible you need to compare first and last item positions(all other items for sure are gonna be visible) according to viewport size.
To initiate recomposition only for changed cells, you can again use derivedStateOf
within item
to convert the indexes to a specific boolean state.
val state = rememberLazyListState()
val fullyVisibleIndices: List<Int> by remember {
derivedStateOf {
val layoutInfo = state.layoutInfo
val visibleItemsInfo = layoutInfo.visibleItemsInfo
if (visibleItemsInfo.isEmpty()) {
emptyList()
} else {
val fullyVisibleItemsInfo = visibleItemsInfo.toMutableList()
val lastItem = fullyVisibleItemsInfo.last()
val viewportHeight = layoutInfo.viewportEndOffset + layoutInfo.viewportStartOffset
if (lastItem.offset + lastItem.size > viewportHeight) {
fullyVisibleItemsInfo.removeLast()
}
val firstItemIfLeft = fullyVisibleItemsInfo.firstOrNull()
if (firstItemIfLeft != null && firstItemIfLeft.offset < layoutInfo.viewportStartOffset) {
fullyVisibleItemsInfo.removeFirst()
}
fullyVisibleItemsInfo.map { it.index }
}
}
}
LazyColumn(
state = state,
contentPadding = PaddingValues(30.dp)
) {
items(100) { index ->
val isVisible by remember(index) {
derivedStateOf {
fullyVisibleIndices.contains(index)
}
}
Text(
index.toString(),
modifier = Modifier
.background(if (isVisible) Color.Green else Color.Transparent)
.padding(30.dp)
)
}
}