我想要 LazyColumn 中的总滚动位置(以 px 为单位)。 列本身有一个 ScrollState ,它有一个值(在文档中描述为以像素为单位的当前滚动位置值),但是 LazyColumn ScrollState 没有这个字段,我想要 LazyColumn 的 Column ScrollState 滚动位置值的完全相同,我如何可以借助 LazyScrollState 来实现吗?
不可能知道确切的滚动位置,但我们可以尝试!
@Composable
fun rememberCurrentOffset(state: LazyListState): State<Int> {
val position = remember { derivedStateOf { state.firstVisibleItemIndex } }
val itemOffset = remember { derivedStateOf { state.firstVisibleItemScrollOffset } }
val lastPosition = rememberPrevious(position.value)
val lastItemOffset = rememberPrevious(itemOffset.value)
val currentOffset = remember { mutableStateOf(0) }
LaunchedEffect(position.value, itemOffset.value) {
if (lastPosition == null || position.value == 0) {
currentOffset.value = itemOffset.value
} else if (lastPosition == position.value) {
currentOffset.value += (itemOffset.value - (lastItemOffset ?: 0))
} else if (lastPosition > position.value) {
currentOffset.value -= (lastItemOffset ?: 0)
} else { // lastPosition.value < position.value
currentOffset.value += itemOffset.value
}
}
return currentOffset
}
也使用
Get previous value of state in Composable - Jetpack Compose解决方案中的
rememberPrevious
。
使用方法
val scroll = rememberLazyListState()
val offset = rememberCurrentOffset(scroll)
// do any thing with the offset state
LazyColumn(
state = scroll,
modifier = Modifier.fillMaxSize()
) {
....
}
通过将
onGloballyPosition{ it.positionInParent()}
修饰符附加到一个或多个项目,可以在项目本身中获得滚动量,无需计算。
然后,这些项目可以使用自己的滚动位置执行所需的操作,例如偏移某些屏幕绘制 y 坐标。
或者,如果您需要父 LazyColumn 中的滚动偏移量,则可以在项目列表的最顶部有一个项目(可能是高度为零的项目,尽管我没有测试过),该项目报告其位置每当它移动时,都会传递给父级(可能通过更新父级传递给该项目的 mutableState )。
我有同样的需求,并且
onGloballyPosition{ it.positionInParent()}
很好地解决了这个问题。
您可以通过
firstVisibleItemScrollOffset
获取它。 val listState = rememberLazyListState()
val itemHeight = with(LocalDensity.current) { 80.dp.toPx() } // Your item height
val scrollPos = listState.firstVisibleItemIndex * itemHeight + listState.firstVisibleItemScrollOffset
Text(text = "scroll: $scrollPos")
LazyColumn(state = listState) {
// Your items here
}
此外,您还可以将滚动位置设置为
listState
,如下所示:
LaunchedEffect(key1 = "Key") {
delay(1000) // To show scroll explicitly, set the delay
listState.scrollBy(itemHeight * 2)
}
它存在于 Column 中的原因是因为它在生成时知道所有项目(行)。
但是 LazyColumn 在任何给定时刻仅显示总视图的一部分,并且当您滚动时,它会不断地重新生成屏幕上的视图(加上可见区域上方和/或下方的几个视图),因此它实际上从未计算所有行的总高度。如果你想获得滚动位置,你必须手动计算它。如果每行的高度相同,效果会很好。但如果高度不同,那么您将无法获得准确的滚动位置(您的计算将根据当前显示的行的高度而波动)。但你必须自己计算一下:
计算所有物品的总大小
val totalItems = lazyListState.layoutInfo.totalItemsCount
val itemLengthInPx = lazyListState.layoutInfo.visibleItemsInfo.firstOrNull()?.size ?: 0
val totalLengthInPx = totalItems * itemLengthInPx
计算当前滚动位置
val scrollPos = (lazyListState.firstVisibleItemIndex * itemLengthInPx) / totalLengthInPx
但正如我之前提到的,此计算取决于每个项目的高度 (
itemLengthInPx
),如果所有视图都相同,则效果非常好。但是您可以看到如果每个视图具有不同的高度,它会如何波动
我创建了这个简单的 LazyListState 扩展来获取当前滚动位置。请注意,这假设列表中的所有项目都具有相同的高度。
fun LazyListState.scrollPos(): Int {
val itemLengthInPx = layoutInfo.visibleItemsInfo.firstOrNull()?.size ?: 0
return (firstVisibleItemIndex * itemLengthInPx) + firstVisibleItemScrollOffset
}