https://kotlinlang.org logo
t

tylerwilson

07/11/2023, 9:19 PM
I am using TabRow/HorizontalPager with three pages, each of them a LazyColumn. I notice that sometimes when i scroll in one, it resets the scroll to top on touch release. Also, when changing pages it resets the scroll to top. Have others seen this, and if so, any solutions or simply a bug in Pager? Thanks!
This is what my composable looks like:
Copy code
val tabs = listOf("Search", "Recommended", "History")
    val pagerState = rememberPagerState(pageCount = { tabs.count() })
    val coroutineScope = rememberCoroutineScope()

    Column(modifier = Modifier.background(MaterialTheme.colorScheme.background)) {
        TabRow(selectedTabIndex = pagerState.currentPage,
            modifier = Modifier
                .fillMaxWidth()
                .wrapContentHeight()
        ) {
            tabs.forEachIndexed { index, title ->
                Tab(selected = pagerState.currentPage == index, onClick = { coroutineScope.launch { pagerState.animateScrollToPage(index) } },
                    Modifier.padding(bottom = 8.dp, top = 12.dp)) {
                        Text(title)
                }
            }
        }
        HorizontalPager(state = pagerState, userScrollEnabled = false) {
            when (pagerState.currentPage) {
                0 -> ProductSearchView(viewModel, callback)
                1 -> ProductRecommendedView(viewModel, callback)
                2 -> ProductHistoryView(viewModel, callback)
            }
        }
    }
t

Timo Drick

07/11/2023, 9:49 PM
Not sure if i understood you problem correctly. But i think it is because the pages are destroyed when not visible. Sometimes it works because the view pager keeps several pages running. E.g. when you swipe to the 3rd page the first page gets destroyed and if you store the scrollstate inside of the composable it gets resettet. In the code i see that you do have a viewmodel maybe try to store the scrollstate in the viewmodel or store the scrollstate outside of the HorizontalPager.
t

tylerwilson

07/11/2023, 9:53 PM
Sorry, I cut off the top few lines:
Copy code
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun ProductLookupView(viewModel: ProductSearchViewModel, callback: (action: String, context: Any?) -> Unit) {
    val loading = viewModel.loading.collectAsState()
    val error = viewModel.error.collectAsState()
so yeah, I do have a viewmodel. I will first try to save scrollstate in this composable, since this a shared viewmodel and i dont want the scroll to persist outside of this view. The first issue i mentioned is only within one page: scroll down, let go, and it scrolls it to the top. I cannot tell who is making it go to the top, but i tried putting the same LazyColumn outside the tabset, and it worked fine. That is why I suspected the pager is somehow telling its child to scroll. More debugging required.
t

Timo Drick

07/11/2023, 10:16 PM
Can you provide the code for the page that is not working?
s

Stylianos Gakis

07/12/2023, 6:16 AM
Storing the scroll state with rememberSaveable wouldn't work here? Not sure about how it'd handle this type of "death" when you scroll far enough from it. One hacky way to solve this, or at least test that it's your actual problem is to make the tab row let pages live even if you are 2 steps away from them. With a 3 step pager that'd mean that none of your options would die (and that all would be initialized together losing laziness of course)
7 Views