Home > other >  Detect when the user lifts their finger (off the screen)
Detect when the user lifts their finger (off the screen)

Time:05-12

We have pointerInput for detecting tap, drag and pan events, and it also provides a handy awaitPointerEventScope, the pointer being the finger, for mobile devices here. Now, we do have a awaitFirstDown() for detecting when the finger first makes contact with the screen, but I can't seem to find an upper equivalent to this method.

I have a little widget that I wish to detect taps on, but the thing is that the app is made for such a use-case that the user might be in weird positions during its use, and so I wished to have it trigger the required action on just a touch and lift of the finger. The paranoia is that the user might accidentally 'drag' their finger (even by a millimeter, android still picks it up), and I do not want that to be the case. I could implement a tap as well as a drag listener, but none of them offer a finger-lift detection, as far as I know.

What solution, if there is one as of now, is suitable for the use-case while adhering to and leveraging the declarative nature of Compose while keeping the codebase to a minimum?

CodePudding user response:

pointerInteropFilter is the way to go

Item(

   Modifier.pointerInteropFilter {

      if (it.action == MotionEvent.ACTION_UP) {
        triggerAction()
      }

      true // Consume touch, return false if consumption is not required here

   }

)

CodePudding user response:

Better way, and what is suggested by Android code if you are not using interoperability with existing View code is Modifier.pointerInput()

A special PointerInputModifier that provides access to the underlying MotionEvents originally dispatched to Compose. Prefer pointerInput and use this only for interoperation with existing code that consumes MotionEvents. While the main intent of this Modifier is to allow arbitrary code to access the original MotionEvent dispatched to Compose, for completeness, analogs are provided to allow arbitrary code to interact with the system as if it were an Android View.

val pointerModifier = Modifier
    .pointerInput(Unit) {
        forEachGesture {

            awaitPointerEventScope {
                
                awaitFirstDown()
               // ACTION_DOWN here
               
                do {
                    
                    //This PointerEvent contains details including
                    // event, id, position and more
                    val event: PointerEvent = awaitPointerEvent()
                    // ACTION_MOVE loop

                    // Consuming event prevents other gestures or scroll to intercept
                    event.changes.forEach { pointerInputChange: PointerInputChange ->
                        pointerInputChange.consumePositionChange()
                    }
                } while (event.changes.any { it.pressed })

                // ACTION_UP is here
            }
        }
}

This answer explains in detail how it works, internals and key points to consider when creating your own gestures.

Also this is a gesture library you can check out for onTouchEvent counterpart and 2 for detectTransformGestures with onGestureEnd callback and returns number of pointers down or list of PointerInputChange in onGesture event. Which can be used as

 Modifier.pointerMotionEvents(
    onDown = {
        // When down is consumed
        it.consumeDownChange()
    },
    onMove = {
        // Consuming move prevents scroll other events to not get this move event
        it.consumePositionChange()
    },
    onUp= {}
    delayAfterDownInMillis = 20
)
  • Related