RecyclerView水平滚动时仅屏蔽ViewPager滑动且不影响垂直滚动的实现问题
问题根因
你当前的实现直接在ACTION_DOWN事件阶段就通知父容器(也就是你要屏蔽的ViewPager)禁止拦截所有后续触摸事件,没有提前判断滚动方向,所以无论用户是水平滑动还是垂直滑动,ViewPager的触摸响应都会被屏蔽,进而影响垂直滚动的正常交互。
修复后实现代码
// 记录触摸初始坐标 private float startX, startY; // 系统预设的滑动判定最小阈值,避免手指抖动触发误判 private int touchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); mRecyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() { @Override public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: // 按下时记录初始坐标,暂时不修改父容器拦截规则 startX = event.getX(); startY = event.getY(); break; case MotionEvent.ACTION_MOVE: // 计算水平、垂直方向的滑动偏移量 float dx = Math.abs(event.getX() - startX); float dy = Math.abs(event.getY() - startY); if (dx > touchSlop && dx > dy) { // 判定为水平滚动,禁止父容器(ViewPager)拦截触摸事件 view.getParent().requestDisallowInterceptTouchEvent(true); } else if (dy > touchSlop) { // 判定为垂直滚动,允许父容器正常处理触摸事件 view.getParent().requestDisallowInterceptTouchEvent(false); } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: // 触摸结束/取消时,恢复父容器的拦截权限,避免影响后续其他交互 view.getParent().requestDisallowInterceptTouchEvent(false); break; } return false; } @Override public void onTouchEvent(@NonNull RecyclerView view, @NonNull MotionEvent event) { } @Override public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { } });
逻辑说明
- 采用系统提供的
scaledTouchSlop作为滑动判定阈值,适配不同分辨率的设备,避免误触 - 仅在明确判定为水平滚动时才屏蔽ViewPager的滑动拦截,垂直滚动场景下完全放开父容器的事件处理权限,不会影响垂直滚动的正常响应
- 触摸结束后主动恢复父容器的拦截权限,避免后续页面其他触摸交互出现异常
- 如果存在多层父容器嵌套的场景,可以递归向上遍历父容器调用
requestDisallowInterceptTouchEvent即可兼容
内容的提问来源于stack exchange,提问作者shehzy
相关产品推荐
相关产品推荐

