I have some problem trying to control the distribution of touch events in my RecycleView. Thus, I have a RecyclerView populating a set of CardViews that mimic a stack of cards (so they overlap each other with a certain movement, although they have a different height value). My current problem is that there is a button on each map, and since the relative displacement of the map is less than the height of the button, this causes the buttons to overlap, and whenever a touch event is dispatched, it starts to propagate from the lower hierarchy of views (from children with the highest number of children).
In accordance with the articles I read ( this , this , as well as this video ). The touch extends depends on the order of the views in the parent view, so the touch will first be passed to the child using the highest index, while I want the touch event to be handled only by the top view and RecyclerView touches (it should also handle drag and drop gestures). I currently use a backup of cards that are aware of their position in the hierarchy of parent views to prevent child abuse, but this is a really ugly way to do this. My assumption is that I should override the RecaViewView dispatchTouchEvent method and correctly send the touch event only to the very top child. However, when I tried this way to do this (which is also pretty awkward):
@Override public boolean dispatchTouchEvent(MotionEvent ev) { View topChild = getChildAt(0); for (View touchable : topChild.getTouchables()) { int[] location = new int[2]; touchable.getLocationOnScreen(location); RectF touchableRect = new RectF(location[0], location[1], location[0] + touchable.getWidth(), location[1] + touchable.getHeight()); if (touchableRect.contains(ev.getRawX(), ev.getRawY())) { return touchable.dispatchTouchEvent(ev); } } return onTouchEvent(ev); }
Only the DOWN button was delivered to the button inside the card (without triggering a click). I would appreciate any advice on how to reverse the distribution of sensory events or delegate a touch event to a specific view. Thank you so much in advance.
EDIT: This is a screenshot of what an example map stack looks like 
Adapter code example:
public class TestAdapter extends RecyclerView.Adapter { List<Integer> items; public TestAdapter(List<Integer> items) { this.items = items; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View v = LayoutInflater.from(parent.getContext()) .inflate(R.layout.test_layout, parent, false); return new TestHolder(v); } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { TestHolder currentHolder = (TestHolder) holder; currentHolder.number.setText(Integer.toString(position)); currentHolder.tv.setTag(position); currentHolder.tv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int pos = (int) v.getTag(); Toast.makeText(v.getContext(), Integer.toString(pos) + "clicked", Toast.LENGTH_SHORT).show(); } }); } @Override public int getItemCount() { return items.size(); } private class TestHolder extends RecyclerView.ViewHolder { private TextView tv; private TextView number; public TestHolder(View itemView) { super(itemView); tv = (TextView) itemView.findViewById(R.id.click); number = (TextView) itemView.findViewById(R.id.number); } } }
and a sample map layout:
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:layout_margin="16dp" android:textSize="24sp" android:id="@+id/number"/> <TextView android:layout_width="wrap_content" android:layout_height="64dp" android:gravity="center" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:layout_margin="16dp" android:textSize="24sp" android:text="CLICK ME" android:id="@+id/click"/> </RelativeLayout> </android.support.v7.widget.CardView>
And here is the code that I use now to solve the problem (I donβt like this approach, I want to find a better way)
public class PositionAwareCardView extends CardView { private int mChildPosition; public PositionAwareCardView(Context context) { super(context); } public PositionAwareCardView(Context context, AttributeSet attrs) { super(context, attrs); } public PositionAwareCardView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public void setChildPosition(int pos) { mChildPosition = pos; } @Override public boolean onInterceptTouchEvent(MotionEvent ev) {
EDIT 2: I forgot to mention that this problem is only present on pre-Lolipop devices, it seems that starting with Lolipop, ViewGroups also take into account elevation when sending touch events
EDIT 3: Here is my current child drawing order:
@Override protected int getChildDrawingOrder(int childCount, int i) { return childCount - i - 1; }
EDIT 4: Finally, I was able to fix the problem thanks to a random user, and this answer , the solution was extremely simple:
@Override public boolean dispatchTouchEvent(MotionEvent ev) { if (!onInterceptTouchEvent(ev)) { if (getChildCount() > 0) { final float offsetX = -getChildAt(0).getLeft(); final float offsetY = -getChildAt(0).getTop(); ev.offsetLocation(offsetX, offsetY); if (getChildAt(0).dispatchTouchEvent(ev)) {