Jetpack Compose之HorizontalPager嵌套动态数量的LazyColumn+Paging3

对于分类展示结构化数据的场景,一般使用Tab+Pager+List的形式。当tab的数量固定时比较好解决,最基础的方式是写n个PagingData和LazyListState:

    val recommendState = rememberLazyListState()
    val recommendData = uiState.recommendPager.collectAsLazyPagingItems()

    val textState = rememberLazyListState()
    val textData = uiState.textPager.collectAsLazyPagingItems()

    val imageState = rememberLazyListState()
    val imageData = uiState.imagePager.collectAsLazyPagingItems()

    Column(modifier = Modifier.fillMaxSize()) {
        JokeTabs(
            tabs = uiState.tabs.map { it.source },
            selected = uiState.selectedTab.source,
            onClick = {
                val index = uiState.tabs.map { it.source }.indexOf(it)
                scope.launch { pagerState.animateScrollToPage(index) }
            }
        )
        HorizontalPager(count = uiState.tabs.size, state = pagerState) { page ->
            when (page) {
                0 -> JokeList(
                    items = recommendData, state = recommendState,
                    headerClickListener = headerClickListener,
                    contentClickListener = contentClickListener,
                    infoClickListener = infoClickListener
                )
                1 -> JokeList(
                    items = textData, state = textState,
                    headerClickListener = headerClickListener,
                    contentClickListener = contentClickListener,
                    infoClickListener = infoClickListener
                )
                2 -> JokeList(
                    items = imageData, state = imageState,
                    headerClickListener = headerClickListener,
                    contentClickListener = contentClickListener,
                    infoClickListener = infoClickListener
                )
                else -> {}
            }
        }
    }
但是这种方法很笨重,需要写很多重复代码,而且无法适应动态数量Tab的形式。解决办法是将LazyColumn的State和PagingData的State放在ViewModel中,而不是放在ui中。

首先,创建UiState:
data class JokeListState(
    val listState: LazyListState,
    val swipeRefreshState: SwipeRefreshState,
    val pagingData: Flow<PagingData<JokeData>>
)
然后在ViewModel中初始化UiState。UiState中三个对象的初始化方法在JetpackCompose提供的remember方法中,没有internal方法,可以直接拿来用。
最后,在ui中引用该UiState:
    val owner = LocalLifecycleOwner.current
    val uiState by vm.uiState.collectAsStateWithLifecycle(lifecycleOwner = owner)

// Pager中的页面
@Composable
private fun JokeList(
    state: JokeListState,
    modifier: Modifier = Modifier,
    headerClickListener: JokeHeaderClickListener,
    contentClickListener: JokeContentClickListener,
    infoClickListener: JokeInfoClickListener
) {
    val pagingData = state.pagingData.collectAsLazyPagingItems()
    val listState = rememberSaveable(saver = LazyListState.Saver) { state.listState }    // 注意使用rememberSaveable保存LazyColumn的状态
    SwipeRefresh(state = state.swipeRefreshState, onRefresh = { pagingData.refresh() }) {
        LazyColumn(modifier = modifier, state = listState) {
            items(pagingData) {
                it?.let {
                    JokeCard(
                        joke = it,
                        headerClickListener = headerClickListener,
                        contentClickListener = contentClickListener,
                        infoClickListener = infoClickListener
                    )
                }
            }
        }
    }
}

以上需要注意的点是需要使用rememberSaveable保存LazyColumn的滑动状态,否则切换Pager的时候会清空该状态

posted @ 2023-02-16 15:13  李振欣  阅读(608)  评论(0编辑  收藏  举报