如何在 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 added 到 LazyColumn
、LazyRow
和 LazyVerticalGrid
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
)
){
...
但是,这会阻止程序滚动。
我想在 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 added 到 LazyColumn
、LazyRow
和 LazyVerticalGrid
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
)
){
...
但是,这会阻止程序滚动。