Does anyone know of a way to capture a click/touch...
# compose
l
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?
z
You could probably use
pointerInput
and await pointed events from the
Initial
pass
l
Thanks a lot @Zach Klippenstein (he/him) [MOD]! I will have to look into that in more detail. 😅
p
@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 😞
l
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.
👍 1
p
@Zach Klippenstein (he/him) [MOD] are you able to help with this one?
z
can you share your code?
p
sure 🙂 this one block the scroll:
Copy code
@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.
z
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.
p
this one produce an error on startup:
Copy code
@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:
Copy code
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:
Copy code
.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()}")
                        }
                    }
                }
            }
        }
z
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!
👍 1