Yousuf Sohail
Yousuf Sohail

Reputation: 603

Jetpack Compose: How to listen column scrolled to end?

I have a compose column that has multiple view elements. I want to detect when the user vertically scrolls the column and reaches its end. How can we do that?

Upvotes: 8

Views: 9515

Answers (3)

unlinked app
unlinked app

Reputation: 31

@Composable
fun LazyListState.OnBottomReached(
    loadMore : () -> Unit
){
    val shouldLoadMore = remember {
        derivedStateOf {
            val lastVisibleItem = layoutInfo.visibleItemsInfo.lastOrNull()
                ?: return@derivedStateOf true
          
            lastVisibleItem.index == layoutInfo.totalItemsCount - 1
        }
    }
    
    // Convert the state into a cold flow and collect
    LaunchedEffect(shouldLoadMore){
        snapshotFlow { shouldLoadMore.value }
            .collect { 
                // if should load more, then invoke loadMore
                if (it) loadMore()
        }
    }
}

The part you are looking for is "derivedStateOf" I believe.

This guy wrote an article about this: https://manavtamboli.medium.com/infinite-list-paged-list-in-jetpack-compose-b10fc7e74768

Upvotes: 3

Phil Dukhov
Phil Dukhov

Reputation: 87794

In Compose you should react on state changes instead of looking for or creating listeners.

To prevent redundant recompositions, in such cases derivedStateOf should be used: it'll trigger recomposition only when produced result, based on other state variables, like scrollState, is changed:

val scrollState = rememberScrollState()
val endReached by remember {
    derivedStateOf {
        scrollState.value == scrollState.maxValue
    }
}

If you need to do some side effect when you change a variable, such as asking for more data, you can do this in Compose in different ways according to side effects documentation. For example, with LaunchedEffect:

if (endReached) {
    LaunchedEffect(Unit) {
        // react on scroll end
    }
}

Upvotes: 14

EunhaEonnie
EunhaEonnie

Reputation: 225

you can use scrollState.value and scrollState.maxValue to check it

val scrollState = rememberScrollState()

Log.i("ScrollValue", "current: ${scrollState.value}, max: ${scrollState.maxValue}")
if (scrollState.value == scrollState.maxValue) {
    // End
}

Column(
    modifier = Modifier
        .fillMaxSize()
        .verticalScroll(scrollState)
) {...}

Upvotes: 4

Related Questions