Search code examples
androidandroid-jetpack-composejetpack-compose-accompanist

Is there any way to make two horizontal pager of accompanist library to work synchronously?


What I am trying to achieve is if there are two horizontal pagers, then on swiping top one to left then the bottom horizontal pager should swipe to right and vice-versa, have tried using pagerState scrollBy method but not getting desired output


Solution

  • First of all, you need to determine which pager is scrolled and which one should follow it. This can be done with isScrollInProgress, I use it inside derivedStateOf to avoid unnecessary re-compositions.

    Then I run LaunchedEffect. I'm passing pair of pager states in needed order, or null, as a key, so LaunchedEffect will be re-launched when scrolling stops/starts. Using snapshotFlow, it is possible to track changes in the result of a block whose calculations depend on state changes.

    PagerState has scroll position information in the properties currentPage and currentPageOffsetFraction. I pass these to scrollToPage to sync the two pagers.

    Column {
        val count = 10
        val firstPagerState = rememberPagerState()
        val secondPagerState = rememberPagerState()
    
        val scrollingFollowingPair by remember {
            derivedStateOf {
                if (firstPagerState.isScrollInProgress) {
                    firstPagerState to secondPagerState
                } else if (secondPagerState.isScrollInProgress) {
                    secondPagerState to firstPagerState
                } else null
            }
        }
        
        // sync both horizontal pagers
        LaunchedEffect(scrollingFollowingPair) {
            val (scrollingState, followingState) = scrollingFollowingPair ?: return@LaunchedEffect
            snapshotFlow { Pair(scrollingState.currentPage, scrollingState.currentPageOffsetFraction) }
                .collect { (currentPage, currentPageOffsetFraction) ->
                    followingState.scrollToPage(
                        page = currentPage,
                        pageOffsetFraction = currentPageOffsetFraction
                    )
                }
        }
    
        HorizontalPager(
            count = count,
            state = firstPagerState,
            modifier = Modifier.weight(1f)
        ) {
            Text(it.toString())
        }
        HorizontalPager(
            count = count,
            state = secondPagerState,
            modifier = Modifier.weight(1f)
        ) {
            Text(it.toString())
        }
    }
    

    Result: