[英]How to check visibility of list item in Jetpack Compose
FlatList
of React Native
has a property viewabilityConfigCallbackPairs
where you can set: React Native
的FlatList
有一个属性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
.使用
offset
和size
属性可以很容易地计算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.