在布置
max()
的项目之前,我尝试在初始数据的子集中找到 LazyRow
。该子集将仅包含可见项目,我需要阅读firstVisibleItemIndex
而不触发重组。
相关代码:
@Composable
fun TestComposable(modifier: Modifier = Modifier) {
val scrollState = rememberLazyListState()
val dataList = mutableListOf<Int>().apply {
repeat(100) {
add((0..100).random())
}
}
val windowSize = 4
LazyRow(
state = scrollState
) {
itemsIndexed(dataList,
key = { index, item -> index }) { index, item ->
val firstIndex = scrollState.firstVisibleItemIndex // <-- Observable and causes recompositions
val endIndex = firstIndex + windowSize
val lastIndex = if (endIndex > dataList.size - 1)
dataList.size - 1
else
endIndex
val max = dataList
.subList(firstIndex, lastIndex) // For simplicity let it be sublist here
.max()
Text(max.toString())
}
}
}
我应该如何在不重新组合的情况下访问
firstVisibleItemIndex
值?
要访问 firstVisibleItemIndex 而不触发 LazyRow 中的重组,您可以将 LaunchedEffect 与 snapshotFlow 结合使用。此方法观察对scrollState.firstVisibleItemIndex的更改并更新MutableState或根据需要执行计算,而不直接将可观察值与可组合重组联系起来。
以下是实施方法:
@Composable
fun TestComposable(modifier: Modifier = Modifier) {
val scrollState = rememberLazyListState()
val dataList = mutableListOf<Int>().apply {
repeat(100) {
add((0..100).random())
}
}
val windowSize = 4
// State to hold the max value
val maxForVisibleItems = remember { mutableStateOf(0) }
// Launch a side effect to observe firstVisibleItemIndex changes
LaunchedEffect(scrollState) {
snapshotFlow { scrollState.firstVisibleItemIndex }
.collect { firstIndex ->
val endIndex = firstIndex + windowSize
val lastIndex = if (endIndex > dataList.size - 1) dataList.size - 1 else endIndex
maxForVisibleItems.value = dataList.subList(firstIndex, lastIndex).maxOrNull() ?: 0
}
}
LazyRow(
state = scrollState
) {
itemsIndexed(dataList, key = { index, item -> index }) { index, item ->
Text(maxForVisibleItems.value.toString()) // Use the precomputed max value
}
}
}
说明:
使用
snapshotFlow
:
snapshotFlow 观察firstVisibleItemIndex 的更改,而不会导致重组。
它捕获协程中的scrollState.firstVisibleItemIndex的值。
更新
LaunchedEffect
中的状态:
在收集块内,计算可见项目的最大值并更新 maxForVisibleItems。
这确保仅当firstVisibleItemIndex更改时才运行计算。
显示最大值: Text 可组合项使用 maxForVisibleItems 中的预先计算值,避免由于直接观察 firstVisibleItemIndex 而导致不必要的重新组合。
处理边缘情况: 如果列表为空或计算没有产生结果,maxOrNull 通过默认回退确保安全处理。