Lukas K-G

    Lukas K-G

    1 year ago
    Does anyone know of a way to capture a click/touch without consuming it? I.e. a transparent overlay over several widgets that “intercepts” the touch, but the control below - i.e. a button - still gets the actual interaction?
    Zach Klippenstein (he/him) [MOD]

    Zach Klippenstein (he/him) [MOD]

    1 year ago
    You could probably use
    pointerInput
    and await pointed events from the
    Initial
    pass
    Lukas K-G

    Lukas K-G

    1 year ago
    Thanks a lot @Zach Klippenstein (he/him) [MOD]! I will have to look into that in more detail. 😅
    Piotr Prus

    Piotr Prus

    1 year ago
    @Lukas K-G did you manage to make it work? I am trying to add
    pointerInput
    on the scrollable list, but awaitPointedEvents is throwing an error: java.lang.IllegalStateException: cannot access currentEvent outside of input dispatch And
    detectVerticalDragGestures
    is blocking my scroll 😞
    Lukas K-G

    Lukas K-G

    1 year ago
    Unfortunately I never got around to testing that due to some unrelated circumstances. I will still need this once I get back to the project though.
    Piotr Prus

    Piotr Prus

    1 year ago
    @Zach Klippenstein (he/him) [MOD] are you able to help with this one?
    Zach Klippenstein (he/him) [MOD]

    Zach Klippenstein (he/him) [MOD]

    1 year ago
    can you share your code?
    Piotr Prus

    Piotr Prus

    1 year ago
    sure 🙂 this one block the scroll:
    @Composable
    fun TestColumn() {
        val listState = rememberScrollState()
        Column(modifier = Modifier
            .fillMaxWidth()
            .verticalScroll(listState)
            .pointerInput(Unit) {
                detectVerticalDragGestures { change, dragAmount ->
                    Log.d("AAAA", "change: $change")
                }
            }) {
            for (index in 1..20) {
                Surface(color = Color.Red) {
                    Text(
                        modifier = Modifier.padding(12.dp),
                        text = "Next number: $index",
                        style = MaterialTheme.typography.h5
                    )
                }
            }
        }
    }
    The log is displayed, the drag gesture is consumed and not passed.
    Zach Klippenstein (he/him) [MOD]

    Zach Klippenstein (he/him) [MOD]

    1 year ago
    Ok that looks pretty straightforward, you’re not like launching weird coroutines and trying to consume events asynchronously - I think that exception you mentioned is a bug, probably.
    Piotr Prus

    Piotr Prus

    1 year ago
    this one produce an error on startup:
    @Composable
    fun TestColumn2() {
        val listState = rememberScrollState()
        Column(modifier = Modifier
            .fillMaxWidth()
            .verticalScroll(listState)
            .pointerInput(Unit) {
                awaitPointerEventScope {
                    Log.d("AAAA", "pointer event: ${this.currentEvent}")
                }
            }) {
            for (index in 1..20) {
                Surface(color = Color.Red) {
                    Text(
                        modifier = Modifier.padding(12.dp),
                        text = "Next number: $index",
                        style = MaterialTheme.typography.h5
                    )
                }
            }
        }
    }
    The error:
    java.lang.IllegalStateException: cannot access currentEvent outside of input dispatch
            at androidx.compose.ui.input.pointer.SuspendingPointerInputFilter$PointerEventHandlerCoroutine.getCurrentEvent(SuspendingPointerInputFilter.kt:419)
    i think I found the solution. The
    awaitPointerEventScope
    needs to be in coroutine scope. I thought the lambda exp of pinterInput is already a coroutineScope 🙂 . The solution:
    .pointerInput(Unit) {
                coroutineScope {
                    forEachGesture {
                        awaitPointerEventScope {
                            val event = awaitPointerEvent()
                            event.changes.forEach { inputChange ->
                                val drag = awaitVerticalDragOrCancellation(inputChange.id)
                                Log.d("AAAA", "drag or cancel change: ${drag?.positionChange()}")
                            }
                        }
                    }
                }
            }
    Zach Klippenstein (he/him) [MOD]

    Zach Klippenstein (he/him) [MOD]

    1 year ago
    Oh, I think the important thing is forEachGesture more than the coroutineScope wrapper
    But I thought that was required by the receiver types, so I’m surprised the first one compiled? I am on my phone, can’t remember how all these fit together. Glad you got it working though!