anzaidemirzoi
anzaidemirzoi

Reputation: 406

LazyColumn inside HorizontalPager becomes scrollable with a delay after page changed

I am working on a an android jetpack compose screen. Simply, the page has a TabRow with 3 tabs. Every tab has LazyColumn which shows some ui components in a scrollable manner. Also, there is one HorizontalPager, which contains these LazyColumns, for the user to swipe between tabs nicely.

Here is the code;

@Composable
fun StatsContent(viewModel: StatsViewModel) {
    val state = viewModel.soloGameStatsState.collectAsStateWithLifecycle()
    LaunchedEffect(LocalContext.current) {
        viewModel.getSoloStats()
    }

    val titles = listOf("Tab 1", "Tab 2", "Tab 3")
    val pagerState = rememberPagerState { titles.size }
    var tabIndex = pagerState.currentPage
    val coroutineScope = rememberCoroutineScope()

    Scaffold(
        topBar = {
            TabRow(selectedTabIndex = tabIndex) {
                titles.forEachIndexed { index, title ->
                    Tab(
                        text = { Text(title) },
                        selected = tabIndex == index,
                        onClick = { tabIndex = index
                            coroutineScope.launch {
                                pagerState.animateScrollToPage(index)
                            }
                        }
                    )
                }
            }
        },
        content = { paddingValues ->
                HorizontalPager(
                    state = pagerState,
                    pageSpacing = 16.dp
                ) {
                    Column(
                        modifier = Modifier
                            .padding(paddingValues)
                            .fillMaxSize(),
                        verticalArrangement = Arrangement.Center,
                        horizontalAlignment = Alignment.CenterHorizontally
                    ) {
                        if (tabIndex == 1 || tabIndex == 0) {
                            RenderStatsOne(state.value)
                        } else if (tabIndex == 2) {
                            RenderStatsTwo(stats = state.value)
                        }
                    }
                }

        }
    )
}
@Composable
fun RenderStatsOne(stats: Stats?) {
    if (stats != null) {
        LazyColumn(
            modifier = Modifier
                .fillMaxSize()
                .paint(
                    painterResource(id = R.drawable.bg_results),
                    contentScale = ContentScale.Crop
                )
        ) {
            item { ...

@Composable
fun RenderStatsTwo(stats: Stats?) {
    if (stats != null) {
        LazyColumn(
            modifier = Modifier
                .fillMaxSize()
                .paint(
                    painterResource(id = R.drawable.bg_results),
                    contentScale = ContentScale.Crop
                )
        ) {
            item { ...

Here is the issue; Once a page change occurred, it does not matter user triggered it with a tab click or did left-right swipe on the pager, the LazyColumn inside the new visible page is becomes scrollable with a significant delay. Therefore, when I change the page and then quickly try to swipe up and down, the HorizontalPager gets this gesture and a page change is performed.

I see that pagerState has a field called isScrollInProgress. This becomes true as the scroll started. LazyColumn gets focus and becomes scrollable, only when this field becomes false. Unfortunately, this becomes false with a significant delay after the page change is completed.

I am looking for a solution which will make the LazyColumn scrollable as soon as the the new page content it fullu visible.

Any help? Thanks a lot in advance.

Upvotes: 2

Views: 480

Answers (1)

pina14
pina14

Reputation: 56

Not sure why this happens, but the issue seems to be related with the spring animation that animateScrollToPage function uses by default. You can reduce the delay by changing the stiffness of the spring animation (the default being used is StiffnessMediumLow):

pagerState.animateScrollToPage(index, animationSpec = spring(stiffness = Spring.StiffnessMedium))

But this doesn't really solve it, it still happens but with a smaller delay. I was able to solve it using the tween animation instead:

pagerState.animateScrollToPage(index, animationSpec = tween(durationMillis = 200))

In this case, as soon as the animation ends the LazyColumn becomes scrollable, and the components inside it, become clickable.

Upvotes: 1

Related Questions