Как отключить и включить прокрутку в LazyColumn / LazyRow в Jetpack Compose?

Я хочу динамически включать и отключать прокрутку программно в файле.

Похоже, что на LazyListState или соответствующие параметры на LazyColumnсам. Как я могу добиться этого в Compose?

3 ответа

Решение

Нет (в настоящее время) встроенного способа сделать это, что является разумным запросом функции.

Тем не менее scrollAPI достаточно гибкий, поэтому мы можем добавить его сами. По сути, мы создаем бесконечный фальшивый свиток на 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
    )
){
    ...

Однако это блокирует программные прокрутки.

Другие вопросы по тегам