繁体   English   中英

如何检查 Jetpack Compose 中列表项的可见性

[英]How to check visibility of list item in Jetpack Compose

React NativeFlatList有一个属性viewabilityConfigCallbackPairs可以设置:

viewabilityConfig: {
    itemVisiblePercentThreshold: 50,
    waitForInteraction: true,
  }

以 50% 的阈值和交互或滚动后检测列表的可见项目。

Jetpack Compose 是否也有类似的东西?

有一些布局信息的LazyListState 但我想知道这个用例是否有任何内置组件/属性。

编辑

我有一个卡片视图列表,我想检测哪些卡片项目(至少 50% 的卡片可见)在显示中可见。 但只有当用户点击卡片或滚动列表时才需要检测。

要获取具有特定阈值的当前可见项目的更新列表,可以使用LazyListState

LazyListState公开了当前可见项目的List<LazyListItemInfo> 使用offsetsize属性可以很容易地计算visibility percent ,因此可以将过滤器应用于可见性列表以达到visibility >= threshold

LazyListItemInfo具有index属性,可用于将LazyListItemInfo映射到传递给LazyColumn的列表中的实际数据项。

fun LazyListState.visibleItems(itemVisiblePercentThreshold: Float) =
    layoutInfo
        .visibleItemsInfo
        .filter {
            visibilityPercent(it) >= itemVisiblePercentThreshold
        }

fun LazyListState.visibilityPercent(info: LazyListItemInfo): Float {
    val cutTop = max(0, layoutInfo.viewportStartOffset - info.offset)
    val cutBottom = max(0, info.offset + info.size - layoutInfo.viewportEndOffset)

    return max(0f, 100f - (cutTop + cutBottom) * 100f / info.size)
}

用法

val list = state.visibleItems(50f) // list of LazyListItemInfo

此列表必须首先映射到LazyColumn中的相应项目。

val visibleItems = state.visibleItems(50f)
            .map { listItems[it.index] }

@Composable
fun App() {
    val listItems = remember { generateFakeListItems().toMutableStateList() }

    val state = rememberLazyListState()

    LazyColumn(Modifier.fillMaxSize(), state = state) {
        items(listItems.size) {
            Item(listItems[it])
        }
    }

    val visibleItems = state.visibleItems(50f)
        .map { listItems[it.index] }

    Log.d(TAG, "App: $visibleItems")
}

fun generateFakeListItems() = (0..100).map { "Item $it" }

LazyListState#layoutInfo包含有关可见项的信息。
由于要应用阈值,因此需要根据视口大小检查第一个和最后一个项目的位置大小 所有其他项目肯定是可见的。

请务必注意,由于您正在阅读state ,因此您应该使用derivedStateOf来避免冗余重组。

就像是:

@Composable
private fun LazyListState.visibleItemsWithThreshold(percentThreshold: Float): List<Int> {

    return remember(this) {
        derivedStateOf {
            val visibleItemsInfo = layoutInfo.visibleItemsInfo
            if (layoutInfo.totalItemsCount == 0) {
                emptyList()
            } else {
                val fullyVisibleItemsInfo = visibleItemsInfo.toMutableList()
                val lastItem = fullyVisibleItemsInfo.last()

                val viewportHeight = layoutInfo.viewportEndOffset + layoutInfo.viewportStartOffset

                if (lastItem.offset + (lastItem.size*percentThreshold) > viewportHeight) {
                    fullyVisibleItemsInfo.removeLast()
                }

                val firstItemIfLeft = fullyVisibleItemsInfo.firstOrNull()
                if (firstItemIfLeft != null &&
                    firstItemIfLeft.offset + (lastItem.size*percentThreshold) < layoutInfo.viewportStartOffset) {
                    fullyVisibleItemsInfo.removeFirst()
                }

                fullyVisibleItemsInfo.map { it.index }
            }
        }
    }.value
}

然后只需使用:

    val state = rememberLazyListState()

    LazyColumn( state = state ){
       //items
    }
    val visibleItems = state.visibleItemsWithThreshold(percentThreshold = 0.5f)

通过这种方式,您可以获得阈值为 50% 的所有可见项的列表。 您可以使用以下方法观察列表:

    LaunchedEffect(visibleItems){
        Log.d(TAG, "App: $visibleItems")
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM