15

Is there a built-in Modifier that disables any gesture detection / pointer input interaction of its children?

e.g.

@Composable
fun Foo() {
    Box(modifier = Modifier.gesturesEnabled(enabled = false)) {
        BasicText(text = "Hello", modifier = Modifier.clickable { // clickable is not enabled
            // ...
        })
    }
}

I could roll my own (very simple) implementation using a CompositionLocal:

val LocalGesturesEnabled = compositionLocalOf { mutableStateOf(true) }

fun Modifier.myClickable(onClick: () -> Unit, enabled: Boolean = true) = composed {
    clickable(enabled = enabled && LocalGesturesEnabled.current.value, onClick)
}

But it won't work with third party composables or with more complex composables like LazyList.

Phil Dukhov
  • 67,741
  • 15
  • 184
  • 220
user16885569
  • 221
  • 1
  • 4
  • 11

1 Answers1

32

I believe the reason for the lack of such a system modifier is that you have to show the user that gestures are disabled by using different states for enabled/disabled controls, or by using a semi-transparent overlay view, etc.

But technically using pointerInput modifier you can get all touch events with awaitPointerEvent.

With the pass = PointerEventPass.Initial parameter you will receive events before all child views, and then you can mark the event as handled with consumeAllChanges, so that children will no longer receive them.

fun Modifier.gesturesDisabled(disabled: Boolean = true) =
    if (disabled) {
        pointerInput(Unit) {
            awaitPointerEventScope {
                // we should wait for all new pointer events
                while (true) {
                    awaitPointerEvent(pass = PointerEventPass.Initial)
                        .changes
                        .forEach(PointerInputChange::consume)
                }
            }
        }
    } else {
        this
    }

If you wanna learn more about custom gesture processing, check out this article

Phil Dukhov
  • 67,741
  • 15
  • 184
  • 220