How Are Android Touch Events Delivered

How are Android touch events delivered?

From Activity viewpoint:

Touch events are delivered first to Activity.dispatchTouchEvent. It's where you may catch them first.

Here they get dispatched to Window, where they traverse View hierarchy, in such order that Widgets that are drawn last (on top of other widgets) have chance to process touch in View.onTouchEvent first. If some View returns true in onTouchEvent, then traversal stops and other Views don't receive touch event.

Finally, if no View consumes touch, it's delivered to Activity.onTouchEvent.

That's all your control. And it's logical that what you see drawn on top of something else, has chance to process touch event before something drawn below it.

How to get the Touch position in android?

@Override
public boolean onTouchEvent(MotionEvent event)
{
int x = (int)event.getX();
int y = (int)event.getY();

switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
}

return false;
}

The three cases are so that you can react to different types of events, in this example tapping or dragging or lifting the finger again.

Controlling touch event propagation in case of overlapping views

CardView uses elevation API on L and before L, it changes the shadow size. dispatchTouchEvent in L respects Z ordering when iterating over children which doesn't happen in pre L.

Looking at the source code:

Pre Lollipop

ViewGroup#dispatchTouchEvent

public boolean dispatchTouchEvent(MotionEvent ev) {
final boolean customOrder = isChildrenDrawingOrderEnabled();
for (int i = childrenCount - 1; i >= 0; i--) {
final int childIndex = customOrder ?
getChildDrawingOrder(childrenCount, i) : i;
final View child = children[childIndex];

...

Lollipop

ViewGroup#dispatchTouchEvent

public boolean dispatchTouchEvent(MotionEvent ev) {
// Check whether any clickable siblings cover the child
// view and if so keep track of the intersections. Also
// respect Z ordering when iterating over children.

ArrayList<View> orderedList = buildOrderedChildList();

final boolean useCustomOrder = orderedList == null
&& isChildrenDrawingOrderEnabled();
final int childCount = mChildrenCount;
for (int i = childCount - 1; i >= 0; i--) {
final int childIndex = useCustomOrder
? getChildDrawingOrder(childCount, i) : i;
final View sibling = (orderedList == null)
? mChildren[childIndex] : orderedList.get(childIndex);

// We care only about siblings over the child
if (sibling == child) {
break;
}
...

The child drawing order can be overridden with custom child drawing order in a ViewGroup, and with setZ(float) custom Z values set on Views.

You might want to check custom child drawing order in a ViewGroup but I think your current fix for the problem is good enough.



Related Topics



Leave a reply



Submit