7
votes

In normal view, we can have onTouchEvent

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        when (event?.action) {
            MotionEvent.ACTION_DOWN -> {}
            MotionEvent.ACTION_MOVE -> {}
            MotionEvent.ACTION_UP -> {}
            else -> return false
        }
        invalidate()
        return true
    }

In Jetpack Compose, I can only find we have the tapGestureFilter in the modifier, which only takes the action from the ACTION_UP only.

Modifier
    .tapGestureFilter { Log.d("Track", "Tap ${it.x} | ${it.y}") }
    .doubleTapGestureFilter { Log.d("Track", "DoubleTap ${it.x} | ${it.y}") }

Is there an equivalent onTouchEvent for Jetpack Compose?

3

3 Answers

12
votes

We have a separate package for that, which is pretty useful. There are two main extension functions that would be suitable for you:

  • pointerInput - docs
  • pointerInteropFilter - docs

If you want to handle and process the event I recommend using pointerInteropFilter which is the analogue of View.onTouchEvent. It's used along with modifier:

Column(modifier = Modifier.pointerInteropFilter {
    when (it.action) {
        MotionEvent.ACTION_DOWN -> {}
        MotionEvent.ACTION_MOVE -> {}
        MotionEvent.ACTION_UP -> {}
        else ->  false
    }
     true
})

That will be Compose adjusted code to your specified View.onTouchEvent sample.

P.S. Don't forget about @ExperimentalPointerInput annotation.

1
votes

Maybe a bit late, but since compose is constantly updating, this is how I do it as of today:

Modifier
    .pointerInput(Unit) {
        detectTapGestures {...}
     }
    .pointerInput(Unit) {
        detectDragGestures { change, dragAmount ->  ...}
    })

We also have detectHorizontalDragGestures and detectVerticalDragGestures among others to help us.

ps: 1.0.0-beta03

0
votes

After did some research, looks like can use dragGestureFilter, mixed with tapGestureFilter

Modifier
    .dragGestureFilter(object: DragObserver {
        override fun onDrag(dragDistance: Offset): Offset {
            Log.d("Track", "onActionMove ${dragDistance.x} | ${dragDistance.y}")
            return super.onDrag(dragDistance)
        }
        override fun onStart(downPosition: Offset) {
            Log.d("Track", "onActionDown ${downPosition.x} | ${downPosition.y}")
            super.onStart(downPosition)
        }
        override fun onStop(velocity: Offset) {
            Log.d("Track", "onStop ${velocity.x} | ${velocity.y}")
            super.onStop(velocity)
        }
    }, { true })
    .tapGestureFilter {
        Log.d("NGVL", "onActionUp ${it.x} | ${it.y}")
    }

The reason still use tagGestureFilter, is because the onStop doesn't provide the position, but just the velocity, hence the tapGestureFilter does help provide the last position (if needed)