解决带侧滑删除功能的垂直RecyclerView中嵌套水平RecyclerView的滚动冲突问题
The issue you're facing is a classic touch event conflict between the parent RecyclerView (with swipe-to-delete functionality) and its nested horizontal RecyclerView. Here's how to resolve it cleanly:
Solution 1: Prevent Parent from Intercepting Touch on Nested RecyclerView
The core idea is to give priority to the horizontal nested RecyclerView when the user interacts with it, so the parent RecyclerView doesn't trigger swipe-to-delete accidentally. We can do this by telling the parent to pause touch event interception during interactions with the nested RV.
Add this touch listener to your horizontal nested RecyclerView inside your parent RecyclerView's adapter onBindViewHolder method:
@Override public void onBindViewHolder(@NonNull ParentViewHolder holder, int position) { // ... your existing data binding logic here // Get reference to your horizontal RecyclerView from the view holder RecyclerView horizontalRv = holder.horizontalRecyclerView; horizontalRv.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: // Block parent from intercepting touch once we start interacting with the nested RV v.getParent().requestDisallowInterceptTouchEvent(true); break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: // Allow parent to resume intercepting touch when interaction ends v.getParent().requestDisallowInterceptTouchEvent(false); break; } // Return false so the RecyclerView itself handles its own scroll logic return false; } }); }
Why This Works
requestDisallowInterceptTouchEvent(true)tells the parent View (your main RecyclerView) to stop intercepting touch events once the user taps on the horizontal nested RecyclerView. This ensures the nested RV can process horizontal scroll gestures without interference.- When the user lifts their finger or the gesture is canceled, we re-enable parent interception so swipe-to-delete works normally on other parts of the list item.
Alternative Solution: Customize SwipeToDeleteCallback
If you prefer handling this directly in your SwipeToDeleteCallback, you can add logic to disable swipe when the touch target is the nested RecyclerView. Here's how:
First, add a helper method to check if the current touch point is inside the nested RecyclerView:
private boolean isTouchOnNestedRecyclerView(RecyclerView.ViewHolder viewHolder, MotionEvent event) { View nestedRv = viewHolder.itemView.findViewById(R.id.your_horizontal_rv_id); if (nestedRv == null) return false; int[] location = new int[2]; nestedRv.getLocationOnScreen(location); float touchX = event.getRawX(); float touchY = event.getRawY(); return touchX >= location[0] && touchX <= location[0] + nestedRv.getWidth() && touchY >= location[1] && touchY <= location[1] + nestedRv.getHeight(); }
Then, override getMovementFlags in your SwipeToDeleteCallback to disable swipe when touching the nested RV:
@Override public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) { // Get the current touch event from the parent RecyclerView MotionEvent event = recyclerView.getMotionEvent(); if (event != null && isTouchOnNestedRecyclerView(viewHolder, event)) { // Disable swipe if touch is on the nested RecyclerView return makeMovementFlags(0, 0); } // Enable left swipe normally for other areas return makeMovementFlags(0, ItemTouchHelper.LEFT); }
Note: This approach relies on accessing the current MotionEvent from the RecyclerView, which works but is slightly less straightforward than the first solution.
Either method will resolve the conflict: users can scroll the horizontal RecyclerView without triggering the parent's swipe-to-delete, and swipe-to-delete functions as expected on other areas of the list item.
内容的提问来源于stack exchange,提问作者BVB09

