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
Android Drawing Separator/Divider Line in Layout
Separate Back Stack For Each Tab in Android Using Fragments
How to Check If Location Services Are Enabled
How to Disable an Android Button
How to Make Surfaceview Transparent
How to Refresh Mediastore on Android
How to Open the "Front Camera" on the Android Platform
Android - Cancel Asynctask Forcefully
Android - Android.View.Inflateexception: Binary Xml File Line #8: Error Inflating Class Fragment
...Have You Declared This Activity in Your Androidmanifest.Xml
Nested Recycler View Height Doesn't Wrap Its Content
Tileprovider Using Local Tiles
How to Enable Logcat/Console in Eclipse For Android
Is Asynctask Really Conceptually Flawed or Am I Just Missing Something
Runtimeexception: Your Content Must Have a Listview Whose Id Attribute Is 'Android.R.Id.List'