androidkotlinandroid-studioscrollandroid-jetpack-compose

How to sync flinging and scrolling by button clicks actions of composable HorizontalPager


I am creating an app using jetpack compose HorizontalPager. The pager can be scrolled using button and by flinging through the pages. When the pager is scrolled using button click, I performed extra action, like logging the current page index as shown in the code below. But the message is not logged when flinging through the pages. I want to know how I can achieve performing extra action when flinging through the pages to sync with what happens when scrolling with button. Here is my code

    private const val TAG = "TAGG"

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun PagerDemo(){
    
    val scope = rememberCoroutineScope()
    val state = rememberPagerState{5}

    Column(
        modifier = Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Row(
            modifier = Modifier.fillMaxWidth(),
            horizontalArrangement = Arrangement.Center
        ) {
            Button(onClick = {
                scope.launch{
                    state.scrollToPage(state.currentPage - 1)
                    Log.d(TAG, "${state.currentPage}")
                }

            }) {
                Text(text = "Backward")
            }
            Spacer(modifier = Modifier.width(12.dp))
            Button(onClick = {
                scope.launch{
                    state.scrollToPage(state.currentPage + 1)
                    Log.d(TAG, "${state.currentPage}")
                }

            }) {
                Text(text = "Forward")
            }
        }

        HorizontalPager(
            state = state,
            key = {state.currentPage},
            pageSize = PageSize.Fill,
        ){
            Box(
                modifier = Modifier.fillMaxSize()
                    .background(Color.Cyan),
                contentAlignment = Alignment.Center,
            ){
                Text(
                    text = "$it",
                    fontSize = 64.sp,
                    fontWeight = FontWeight.Bold,
                    textAlign = TextAlign.Center,
                )
            }
        }


    }
}

Solution

  • You can try to use a LaunchedEffect. It allows to trigger side-effects whenever a key variable changes. In your case, you can try to use it like this:

    val state = rememberPagerState{5}
    LaunchedEffect(state.settledPage) {
        Log.d(TAG, "${state.currentPage}")
    }
    

    We are observing the settledPage attribute from the [PagerState][3]. It represents the index of the currently settled page, meaning the index of the page after any scrolling animation was finished. Whenever the settledPage changes, the LaunchedEffect will be executed.
    This will happen both if the scroll was triggered programmatically or by a swipe gesture. You can thus remove the Log.d() statement from your button.

    If you instead want to print the log when the scrolling animation might still be in progress, use currentPage instead.