In the old Android View paradigm, a view could listen for MotionEvents without consuming them. DispatchTouchEvent
or OnTouchEvent
could simply return "false", and the MotionEvent would pass through layer after layer of view until something returned "true", at which time the MotionEvent was consumed and never passed onto lower-level views.
How do you do that in Jetpack Compose (JC)?
The JC touch listener Modifier.pointerInteropFilter
consumes every MotionEvent it detects, and never passes MotionEvents down regardless of whether it returns "true" or "false. (This feels like a bug to me, but it's what we have to work with.)
JC listeners such as Modifier.pointerInput.detectDragGestures
and Modifier.pointerInput.detectTapGestures
all consume their input events when they detect a series of events that matches what they are looking for.
This makes it difficult (but surely not impossible?) to, for instance, conditionally consume an input event if it's made by a pen, but pass that event onto the next Composable (or even the next listener in the same Composable) if it's made by a finger.
This same question was asked here, in a narrower sense, but it was never answered and the OP still seems to be struggling to work around the limitation.
The only way I can think of to work around this bug/limitation is to manually pass MotionEvents onto other Composables.
In the old View paradigm, you could manually target a View's onTouchEvent
method, and pass a MotionEvent directly to that view for handling. That was nice because, for instance, you could conditionally pass finger touches onto View, which would then take care of its own scrolling, but intercept all pen touches and use them to draw rather than scroll.
But how on earth do you pass input events directly to a Composable that is sitting underneath another Composable? Or, assuming I have to do all this in one,giant Composable rather than in layers of Composables, how do you even pass touch events around inside a Composable?
I'd be happy with either solution: not consuming input events/MotionEvents in the first place, and letting them pass down till something wants them; or manually passing them around.
But I can't figure out how to do either!
I'd also be satisfied with an answer telling me I'm erroneously bringing View-style thinking to Composables, but could you kindly outline how I should be thinking, when it comes to conditionally using input events and pointerInput
modifiers to (in the example I've been using) either draw on a Composable, or scroll it?
Is there the equivalent of Python's super() feature, where you detect (for instance) a drag gesture, and if it's a drag made by a finger, do the Composable's default (ie scroll)?
detectDragGestures
are marking touches as consumed. If you need to override this behaviour you can check out this answer. It's about Compose Desktop but in Android it work the same. β Vitrics