Why are my pointerInput PointerEvents being replayed in Jetpack Compose?

24 Views Asked by At

I am currently trying to implement some functionality that requires me to listen for and react to N simultaneous Press & Release touch events on different UI elements (in a Grid implementation using lazy col/row) in my Jetpack compose UI. I am seeing some behaviour that doesn't seem correct to me.

It appears that every time I press i get the event for that press and any presses before it. The presses accumulate and replay. Then when I release the first release replays all the previous press events -1 each time until the last release which just releases the last press as expected.

Below is a simplified version of my code and the output from the log statements:

Code:

fun MyView(
    state: MyState,
    onIntent: (Intent) -> Unit = LocalOnIntent.current
) {
    Box(
        modifier = Modifier
            .size(60.dp)
            .background(Color(state.color))
            .pointerInput(state) {
                awaitPointerEventScope {
                    while (true) {
                        val event: PointerEvent = awaitPointerEvent()
                        if (event.type == PointerEventType.Press || event.type == PointerEventType.Release) {
                            Logger.i { "awaitPointerEvent() ${event.changes.first().id} -:- ${event.type}" }
                        }
                    }
                }
            }
    )
}


Output:

First item pressed:

awaitPointerEvent() PointerId(value=1) : Press

Second item pressed:

awaitPointerEvent() PointerId(value=1) : Press
awaitPointerEvent() PointerId(value=2) : Press

Third item pressed:

awaitPointerEvent() PointerId(value=1) : Press
awaitPointerEvent() PointerId(value=2) : Press
awaitPointerEvent() PointerId(value=3) : Press


Third item released:

awaitPointerEvent() PointerId(value=1) : Release
awaitPointerEvent() PointerId(value=2) : Release
awaitPointerEvent() PointerId(value=3) : Release

Second item released:

awaitPointerEvent() PointerId(value=1) : Release
awaitPointerEvent() PointerId(value=2) : Release

First item released:

awaitPointerEvent() PointerId(value=1) : Release

Desired output:


First item pressed:

awaitPointerEvent() PointerId(value=1) : Press

Second item pressed:

awaitPointerEvent() PointerId(value=2) : Press

Third item pressed:

awaitPointerEvent() PointerId(value=3) : Press

Third item released:

awaitPointerEvent() PointerId(value=3) : Release

Second item released:

awaitPointerEvent() PointerId(value=2) : Release

First item released:

awaitPointerEvent() PointerId(value=1) : Release

I did figure out a convoluted workaround whereby I manage all the pressed states from the event.changes list in a map but I really don't like having to do this. It feels like there must be a better way, maybe I have a weird bug, I'm using something wrong or missing something?

0

There are 0 best solutions below