简体   繁体   English

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

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

FlatList of React Native has a property viewabilityConfigCallbackPairs where you can set: React NativeFlatList有一个属性viewabilityConfigCallbackPairs可以设置:

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

to detect visible items of the list with threshold of 50% and after interaction or scroll.以 50% 的阈值和交互或滚动后检测列表的可见项目。

Does Jetpack Compose also have something similar to this? Jetpack Compose 是否也有类似的东西?

There is LazyListState with some layout info.有一些布局信息的LazyListState But I wonder if there is anything built-in component/property for this use case.但我想知道这个用例是否有任何内置组件/属性。

Edit编辑

I have a list of cardviews and I want to detect which card items (at least 50% of card is visible) are visible on display.我有一个卡片视图列表,我想检测哪些卡片项目(至少 50% 的卡片可见)在显示中可见。 But it needs to be detected only when the card is clicked or list is scrolled by user.但只有当用户点击卡片或滚动列表时才需要检测。

To get an updating list of currently visible items with a certain threshold LazyListState can be used.要获取具有特定阈值的当前可见项目的更新列表,可以使用LazyListState

LazyListState exposes the list of currently visible items List<LazyListItemInfo> . LazyListState公开了当前可见项目的List<LazyListItemInfo> It's easy to calculate visibility percent using offset and size properties, and thus apply a filter to the visible list for visibility >= threshold .使用offsetsize属性可以很容易地计算visibility percent ,因此可以将过滤器应用于可见性列表以达到visibility >= threshold

LazyListItemInfo has index property, which can be used for mapping LazyListItemInfo to the actual data item in the list passed to LazyColumn . 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)
}

Usage用法

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

This list has to be mapped first to corresponding items in LazyColumn .此列表必须首先映射到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" }

The LazyListState#layoutInfo contains information about the visible items . LazyListState#layoutInfo包含有关可见项的信息。
Since you want to apply a threshold you need to check the first and last item positions and size according to viewport size .由于要应用阈值,因此需要根据视口大小检查第一个和最后一个项目的位置大小 All other items are for sure visible.所有其他项目肯定是可见的。

It is important to note that since you are reading the state you should use derivedStateOf to avoid redundant recompositions.请务必注意,由于您正在阅读state ,因此您应该使用derivedStateOf来避免冗余重组。

Something like:就像是:

@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
}

and then just use:然后只需使用:

    val state = rememberLazyListState()

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

In this way you have the list of all the visible items with a threshold of 50%.通过这种方式,您可以获得阈值为 50% 的所有可见项的列表。 You can observe the list using something:您可以使用以下方法观察列表:

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

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

相关问题 如何处理 Jetpack Compose 中文本的可见性? - How to handle visibility of a Text in Jetpack Compose? Jetpack Compose:如何在 LazyVerticalGrid 中将项目居中? - Jetpack Compose: How to center an item in LazyVerticalGrid? 如何在 jetpack compose 的 LazyColumn 中添加项目? - How to add item in LazyColumn in jetpack compose? 如何在 Jetpack Compose 中将 Surface 中的 Item 居中 - How to center Item inside Surface in jetpack compose 如何在 LazyColumn jetpack compose 的底部粘贴项目 - How to stick item at bottom in LazyColumn jetpack compose Jetpack 撰写如何跳过 LazyVerticalGrid / java.lang.IllegalStateException 中的一项:检查失败 - Jetpack compose how to skip one item in a LazyVerticalGrid / java.lang.IllegalStateException: Check failed 使用 List as State 时,如何在 Jetpack Compose 中的 item`attribute 更改时更新 UI? - When using List as State, how to update UI when item`attribute change in Jetpack Compose? 如何在 android jetpack compose 中相互重叠列表项? - How can i overlap list item on each other in android jetpack compose? 如何在 Jetpack Compose 中制作无穷无尽的列表 - How to make an endless list in Jetpack Compose 如何在 Jetpack Compose 中为动态列表的元素设置动画? - How to animate elements of a dynamic list in Jetpack Compose?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM