LazyRow 不可观察的firstVisibleItemIndex?

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

在布置

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
值?

android android-jetpack-compose android-jetpack-compose-lazy-column
1个回答
0
投票

要访问 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 通过默认回退确保安全处理。

© www.soinside.com 2019 - 2024. All rights reserved.