如何知道在 Jetpack Compose 的惰性行的视口中完全可见的项目?
How to know items which are fully visible in the view port of a lazy row in jetpack compose?
我有一个包含项目的惰性行。现在我想 API 调用在用户滚动惰性行时在视口中完全可见的项目。
我试过以下代码:
listState = rememberLazyListState()
LaunchedEffect(listState){
snapshotFlow { listState.firstVisibleItemIndex }
.collectLatest{
Log.d("printed Item", listState.firstVisibleItemIndex.toString())
}}
这段代码的问题是:
- 即使第 2 项占据视口,除非第 1 项完全不可见,否则不会打印它。
- 对于平板电脑,由于其屏幕尺寸较大,即使屏幕上有 2 个可见项目,也只会对第一个可见项目进行 API 调用。请参考截图。
当第一项部分可见且第二项完全可见时
[1]: https://i.stack.imgur.com/l5QcB.jpg
当第二个图块完全可见而第一个图块完全不可见时
[2]: https://i.stack.imgur.com/6rmiQ.jpg
对于 2 项完全可见的平板电脑
[3]: https://i.stack.imgur.com/QYRTI.jpg
谁能告诉我如何解决我的问题?提前致谢。
有关可见项目的所有信息都可以在 state.layoutInfo
中找到。要检查该项目是否可见,您需要根据视口大小比较第一个和最后一个项目的位置(所有其他项目肯定会可见)。
val state = rememberLazyListState()
val fullyVisibleIndices: List<Int> by remember {
derivedStateOf {
val layoutInfo = state.layoutInfo
val visibleItemsInfo = layoutInfo.visibleItemsInfo
if (visibleItemsInfo.isEmpty()) {
emptyList()
} else {
val fullyVisibleItemsInfo = visibleItemsInfo.toMutableList()
val lastItem = fullyVisibleItemsInfo.last()
val viewportHeight = layoutInfo.viewportEndOffset + layoutInfo.viewportStartOffset
if (lastItem.offset + lastItem.size > viewportHeight) {
fullyVisibleItemsInfo.removeLast()
}
val firstItemIfLeft = fullyVisibleItemsInfo.firstOrNull()
if (firstItemIfLeft != null && firstItemIfLeft.offset < layoutInfo.viewportStartOffset) {
fullyVisibleItemsInfo.removeFirst()
}
fullyVisibleItemsInfo.map { it.index }
}
}
}
LazyColumn(
state = state,
contentPadding = PaddingValues(30.dp)
) {
items(100) {
Text(
it.toString(),
modifier = Modifier
.background(if (fullyVisibleIndices.contains(it)) Color.Green else Color.Transparent)
.padding(30.dp)
)
}
}
不确定您将如何在现实生活中使用此信息,如果您确实需要更新项目视图,出于性能原因,最好将此逻辑移动到每个 item
中,以免触发重新组合整个LazyColumn
我有一个包含项目的惰性行。现在我想 API 调用在用户滚动惰性行时在视口中完全可见的项目。
我试过以下代码:
listState = rememberLazyListState()
LaunchedEffect(listState){
snapshotFlow { listState.firstVisibleItemIndex }
.collectLatest{
Log.d("printed Item", listState.firstVisibleItemIndex.toString())
}}
这段代码的问题是:
- 即使第 2 项占据视口,除非第 1 项完全不可见,否则不会打印它。
- 对于平板电脑,由于其屏幕尺寸较大,即使屏幕上有 2 个可见项目,也只会对第一个可见项目进行 API 调用。请参考截图。
当第一项部分可见且第二项完全可见时 [1]: https://i.stack.imgur.com/l5QcB.jpg
当第二个图块完全可见而第一个图块完全不可见时 [2]: https://i.stack.imgur.com/6rmiQ.jpg
对于 2 项完全可见的平板电脑 [3]: https://i.stack.imgur.com/QYRTI.jpg
谁能告诉我如何解决我的问题?提前致谢。
有关可见项目的所有信息都可以在 state.layoutInfo
中找到。要检查该项目是否可见,您需要根据视口大小比较第一个和最后一个项目的位置(所有其他项目肯定会可见)。
val state = rememberLazyListState()
val fullyVisibleIndices: List<Int> by remember {
derivedStateOf {
val layoutInfo = state.layoutInfo
val visibleItemsInfo = layoutInfo.visibleItemsInfo
if (visibleItemsInfo.isEmpty()) {
emptyList()
} else {
val fullyVisibleItemsInfo = visibleItemsInfo.toMutableList()
val lastItem = fullyVisibleItemsInfo.last()
val viewportHeight = layoutInfo.viewportEndOffset + layoutInfo.viewportStartOffset
if (lastItem.offset + lastItem.size > viewportHeight) {
fullyVisibleItemsInfo.removeLast()
}
val firstItemIfLeft = fullyVisibleItemsInfo.firstOrNull()
if (firstItemIfLeft != null && firstItemIfLeft.offset < layoutInfo.viewportStartOffset) {
fullyVisibleItemsInfo.removeFirst()
}
fullyVisibleItemsInfo.map { it.index }
}
}
}
LazyColumn(
state = state,
contentPadding = PaddingValues(30.dp)
) {
items(100) {
Text(
it.toString(),
modifier = Modifier
.background(if (fullyVisibleIndices.contains(it)) Color.Green else Color.Transparent)
.padding(30.dp)
)
}
}
不确定您将如何在现实生活中使用此信息,如果您确实需要更新项目视图,出于性能原因,最好将此逻辑移动到每个 item
中,以免触发重新组合整个LazyColumn