Как отключить и включить прокрутку в LazyColumn / LazyRow в Jetpack Compose?
Я хочу динамически включать и отключать прокрутку программно в файле.
Похоже, что на
LazyListState
или соответствующие параметры на
LazyColumn
сам. Как я могу добиться этого в Compose?
3 ответа
Нет (в настоящее время) встроенного способа сделать это, что является разумным запросом функции.
Тем не менее
scroll
API достаточно гибкий, поэтому мы можем добавить его сами. По сути, мы создаем бесконечный фальшивый свиток на
MutatePriority.PreventUserInput
для предотвращения прокрутки, а затем используйте прокрутку с тем же приоритетом, чтобы отменить первую «прокрутку» и снова включить прокрутку.
Вот две служебные функции на
LazyListState
для отключения / повторного включения прокрутки и демонстрации их обоих в действии (потребуется некоторый импорт, но 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)
}
}
}
}
Решение @Ryan хорошо работает, если вам нужно полностью отключить прокрутку.
В моем случае я хочу отключить прокрутку прикосновениями, но оставить возможность прокрутки программно.
Поэтому я блокирую прокрутку с помощью модификатор:
var gesturesDisabled by remember { mutableStateOf(false) }
LazyColumn(
state = state,
Modifier
.fillMaxWidth()
.gesturesDisabled(gesturesDisabled)
) {
}
gesturesDisabled
модификатор:
fun Modifier.gesturesDisabled(disabled: Boolean = true) =
pointerInput(disabled) {
// if gestures enabled, we don't need to interrupt
if (!disabled) return@pointerInput
awaitPointerEventScope {
// we should wait for all new pointer events
while (true) {
awaitPointerEvent(pass = PointerEventPass.Initial)
.changes
.forEach(PointerInputChange::consumeAllChanges)
}
}
}
Это также заблокирует любые другие касания , поэтому я создал этот запрос функции , убедитесь, что вы его отметили, если вам нужна как программная прокрутка, так и не отключение касаний внутри представления.
NestedScrollConnection позволяет использовать любую прокрутку, примененную к ленивому столбцу или строке. При значении true используется весь доступный свиток. Если false, ничего не используется, и прокрутка происходит нормально. С помощью этой информации вы можете увидеть, как это можно расширить для медленной/быстрой прокрутки, возвращая смещение, кратное некоторому коэффициенту.
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
)
){
...
Однако это блокирует программные прокрутки.