如何在 Jetpack Compose 中禁用和启用 LazyColumn/LazyRow 中的滚动?

How to disable and enable scrolling in LazyColumn/LazyRow in Jetpack Compose?

我想在 LazyColumn 中以编程方式动态启用和禁用滚动。

LazyListState似乎没有任何相关功能或LazyColumn本身没有相关参数。我怎样才能在 Compose 中实现这一点?

(目前)没有内置的方法来执行此操作,这是一个合理的功能请求。

然而,scroll API 足够灵活,我们可以自己添加它。基本上,我们在 MutatePriority.PreventUserInput 处创建一个永无止境的假滚动来防止滚动,然后使用相同优先级的无操作滚动来取消第一个“滚动”并重新启用滚动。

这里有两个关于 LazyListState 到 disable/re-enable 滚动的实用函数,以及它们的实际演示(需要一些导入,但 Android Studio 应该建议它们用于你)。

请注意,因为我们正在控制滚动来执行此操作,所以调用 reenableScrolling 也会取消任何正在进行的滚动或滑动(也就是说,您应该只在滚动被禁用并且您想要重新启用它,而不仅仅是确认它已启用)。

fun LazyListState.disableScrolling(scope: CoroutineScope) {
    scope.launch {
        scroll(scrollPriority = MutatePriority.PreventUserInput) {
            // Await indefinitely, blocking scrolls
            awaitCancellation()
        }
    }
}

fun LazyListState.reenableScrolling(scope: CoroutineScope) {
    scope.launch {
        scroll(scrollPriority = MutatePriority.PreventUserInput) {
            // Do nothing, just cancel the previous indefinite "scroll"
        }
    }
}

@Composable
fun StopScrollDemo() {
    val scope = rememberCoroutineScope()
    val state = rememberLazyListState()
    Column {
        Row {
            Button(onClick = { state.disableScrolling(scope) }) { Text("Disable") }
            Button(onClick = { state.reenableScrolling(scope) }) { Text("Re-enable") }
        }
        LazyColumn(Modifier.fillMaxWidth(), state = state) {
            items((1..100).toList()) {
                Text("$it", fontSize = 24.sp)
            }
        }
    }
}

1.2.0-alpha01 userScrollEnabled was addedLazyColumnLazyRowLazyVerticalGrid


1.1.0及更早版本的回答:

@Ryan 的解决方案还将禁用以编程方式调用的滚动。

这是this feature request中维护者提出的解决方案。它将禁用滚动,允许编程滚动以及子视图触摸。

private val VerticalScrollConsumer = object : NestedScrollConnection {
    override fun onPreScroll(available: Offset, source: NestedScrollSource) = available.copy(x = 0f)
    override suspend fun onPreFling(available: Velocity) = available.copy(x = 0f)
}

private val HorizontalScrollConsumer = object : NestedScrollConnection {
    override fun onPreScroll(available: Offset, source: NestedScrollSource) = available.copy(y = 0f)
    override suspend fun onPreFling(available: Velocity) = available.copy(y = 0f)
}

fun Modifier.disabledVerticalPointerInputScroll(disabled: Boolean = true) =
    if (disabled) this.nestedScroll(VerticalScrollConsumer) else this

fun Modifier.disabledHorizontalPointerInputScroll(disabled: Boolean = true) =
    if (disabled) this.nestedScroll(HorizontalScrollConsumer) else this

用法:

LazyColumn(
    modifier = Modifier.disabledVerticalPointerInputScroll()
) {
    // ...
}

NestedScrollConnection 允许您使用应用于惰性列或行的任何滚动。当为真时,所有可用的卷轴都被消耗掉。如果为 false,则 none 被消耗并且滚动正常发生。有了这些信息,您可以看到如何通过按某个因子返回偏移倍数来扩展 slow/fast 滚动。

fun Modifier.scrollEnabled(
    enabled: Boolean,
) = nestedScroll(
    connection = object : NestedScrollConnection {
        override fun onPreScroll(
            available: Offset,
            source: NestedScrollSource
        ): Offset = if(enabled) Offset.Zero else available
    }
)

可以这样使用:

LazyColumn(
    modifier = Modifier.scrollEnabled(
        enabled = enabled, //provide a mutable state boolean here
    )
){
    ...

但是,这会阻止程序滚动。