防止LazyColumn每次数据变化时闪烁?

问题描述 投票:0回答:1

我正在将 paging3 库与 Compose Multiplatform 结合使用。它正在工作,但我注意到每次收到新的分页数据时,消耗分页数据的组件都会重新渲染(可见闪存)。我相信这是因为检查加载或错误状态的when语句。

我想添加distinctUntilChangedBy来按events.loadstate.refresh进行过滤,但在调用collectAsLazyPagingItems之前,它在流程上不可用。

我应该如何修改此代码,以便它不会在每次消息事件数量发生变化时重新渲染?我只想对列表中的更改进行动画处理,而不渲染整个组件,这会导致现在出现明显的闪烁?

这基本上是一个聊天列表。每次收到新的聊天消息,都会将其插入数据库,并使分页数据失效,以加载最新的消息。

@Composable
fun MessageList(
    pager: Flow<PagingData<MessageEvent>>?,
    modifier: Modifier = Modifier,
) {
    pager?.let { flow ->
        val events = flow.collectAsLazyPagingItems()
        when (events.loadState.refresh) {
            LoadStateLoading -> {
                CenteredProgressIndicator()
            }
            is LoadStateError -> {
                val errorState = events.loadState.refresh as LoadStateError
                ShowError(errorState)
            }
            else -> {
                if (events.itemCount > 0) {
                    LazyColumn {
                        items(events.itemCount) { index ->
                            events[index]?.let {
                                MessageRow(it)
                            }
                        }
                    }
                } else {
                    NoMessagesAvailable(modifier)
                }
            }
        }
    }
}
android-jetpack-compose multiplatform paging3
1个回答
0
投票

发生闪烁是因为在刷新列表时,您在很短的时间内将

loadState
设置为
LoadStateLoading
。因此,在很短的时间内,会显示
CenteredProgressIndicator()

您尚未在设置

loadState
的位置提供代码。但你可以做些什么来解决这个问题:

  • 仅在初始加载时显示
    CenteredProgressIndicator()
    (当列表数据仍为空时)
  • 当列表中已经有数据时刷新时,而是在列表上方显示另一个加载指示器,如
    PullRefresh
    :

为了实现此行为,您可以调整逻辑并引入另一个 loadState:

  • LoadStateLoading
    用于列表为空时的初始加载
  • LoadStateRefreshing
    用于当列表中已有数据时刷新

然后根据LoadState,显示相应的加载动画:

when (events.loadState.refresh) {
    LoadStateLoading -> {
        CenteredProgressIndicator()
    }
    is LoadStateError -> {
        // ...
    }
    else -> {
        // Code for SwipeRefresh
        var refreshing by remember { mutableStateOf(false) }
        val state = rememberPullRefreshState(refreshing)
           
        if (events.loadState.refresh.equals(LoadStateRefresh) {
            refreshing = true
        }

        Box() {
            LazyColumn(Modifier.fillMaxSize()) {
                // your LazyColumn
            }

            // small circular loading indicator
            PullRefreshIndicator(refreshing, state, Modifier.align(Alignment.TopCenter))
        }
        
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.