I have two tabs: Video and Magazine.
The screens for both tabs are identical, utilizing Jetpack Compose for the UI.
Data is fetched using the Paging 3 library from a common API endpoint, differentiated by a query parameter to return either a list of videos or magazines.
However, when switching between the tabs, the state is not retained—both the scroll state and the paging data are lost and starts from position 0 in the list.
How can I preserve the state (including scroll position and paging data) when switching tabs in Jetpack Compose?
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun MainScreen(
modifier: Modifier = Modifier,
categoryData: CategoryData?
) {
if (categoryData == null) {
return
}
val items = categoryData.categories
val pagerState = rememberPagerState(pageCount = { items.size })
var selectedTabIndex by rememberSaveable { mutableIntStateOf(0) }
LaunchedEffect(key1 = selectedTabIndex) {
pagerState.scrollToPage(selectedTabIndex)
}
Box(
Modifier.fillMaxSize()
) {
HorizontalPager(
state = pagerState,
userScrollEnabled = false
) { page ->
FeedScreen(selectedTabIndex, categoryData.categories[selectedTabIndex].id) {}
}
Box {
LazyRow(
modifier = Modifier
.fillMaxWidth()
.scrollable(
state = rememberScrollState(),
orientation = Orientation.Horizontal
),
verticalAlignment = Alignment.CenterVertically
) {
itemsIndexed(items) { index, currentTab ->
CustomTab(currentTab.name, selectedTabIndex == index, index) { pos ->
selectedTabIndex = pos
}
}
}
}
}
}`
This is my VerticalViewPager
@OptIn(
ExperimentalFoundationApi::class, ExperimentalPermissionsApi::class
)
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
@Composable
fun FeedScreen(
selectedTabIndex: Int,
tabId: Int
) {
val viewModel: MainScreenViewModel = viewModel()
viewModel.requestedTabId = tabId
val feedItems = viewModel.feedItems.collectAsLazyPagingItems()
val pagerState = rememberPagerState(pageCount = { feedItems.itemCount })
VerticalPager(
state = pagerState,
modifier = Modifier
.fillMaxSize()
.background(LokalTheme.colors.baseBlack)
.clickable(
indication = null,
interactionSource = remember { MutableInteractionSource() }) {
}
.zIndex(0f),
beyondBoundsPageCount = 3,
) { page ->
val item = feedItems[page]
when (item) {
is PostData.VideoData -> {
//Display VideoCard
}
is PostData.MagazineCardData -> {
//Display MagazineCard
}
}
}
}
Tried saving the data in ViewModel to maintain the states but this did not work.
I’m expecting the tabs to retain their scroll position & data when we switch between them.