LazyColumn Jetpack Compose 中的当前滚动位置值(以像素为单位)

问题描述 投票:0回答:5

我想要 LazyColumn 中的总滚动位置(以 px 为单位)。 列本身有一个 ScrollState ,它有一个值(在文档中描述为以像素为单位的当前滚动位置值),但是 LazyColumn ScrollState 没有这个字段,我想要 LazyColumn 的 Column ScrollState 滚动位置值的完全相同,我如何可以借助 LazyScrollState 来实现吗?

android scroll android-jetpack-compose android-jetpack lazycolumn
5个回答
7
投票

不可能知道确切的滚动位置,但我们可以尝试!

@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()
) {
    ....
}

3
投票

通过将

onGloballyPosition{ it.positionInParent()}
修饰符附加到一个或多个项目,可以在项目本身中获得滚动量,无需计算。

然后,这些项目可以使用自己的滚动位置执行所需的操作,例如偏移某些屏幕绘制 y 坐标。

或者,如果您需要父 LazyColumn 中的滚动偏移量,则可以在项目列表的最顶部有一个项目(可能是高度为零的项目,尽管我没有测试过),该项目报告其位置每当它移动时,都会传递给父级(可能通过更新父级传递给该项目的 mutableState )。

我有同样的需求,并且

onGloballyPosition{ it.positionInParent()}
很好地解决了这个问题。


1
投票

您可以通过

firstVisibleItemScrollOffset
获取它。
('androidx.activity:activity-compose:1.3.1')

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

0
投票

它存在于 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
),如果所有视图都相同,则效果非常好。但是您可以看到如果每个视图具有不同的高度,它会如何波动


0
投票

我创建了这个简单的 LazyListState 扩展来获取当前滚动位置。请注意,这假设列表中的所有项目都具有相同的高度。

fun LazyListState.scrollPos(): Int {
    val itemLengthInPx = layoutInfo.visibleItemsInfo.firstOrNull()?.size ?: 0
    return (firstVisibleItemIndex * itemLengthInPx) + firstVisibleItemScrollOffset
}
© www.soinside.com 2019 - 2024. All rights reserved.