如今咱们有竖向滑动的RecyclerView,在每一个item内部又嵌套了一个横向滑动的RecyclerView,那么咱们手指在滑动RecyclerVIew时,究竟是竖向的响应仍是横向的响应呢?java
如图:红色线为手指滑动距离,右上方滑动到左下方;绿色为竖向滑动距离;蓝色为横向滑动距离;咱们的指望是若是手指滑动的横向距离大于竖向距离的话就响应竖向的外层RecyclerVIew的滑动;若是手指移动的竖向距离大于横向距离,则滑动内部的横向的RecyclerView。git
总体效果以下,完整项目:https://github.com/buder-cp/CustomView/tree/master/buder_DN_view/buderdn14github
咱们继承RecyclerView,重写其中的onInterceptTouchEvent方法,根据咱们须要的业务逻辑去实现事件拦截:3d
public boolean onInterceptTouchEvent(MotionEvent e) { if (e == null) { return false; } int action = MotionEventCompat.getActionMasked(e); int actionIndex = MotionEventCompat.getActionIndex(e); switch (action) { case MotionEvent.ACTION_DOWN: scrollPointerId = MotionEventCompat.getPointerId(e, 0); initialTouchX = Math.round(e.getX() + 0.5f); initialTouchY = Math.round(e.getY() + 0.5f); return super.onInterceptTouchEvent(e); case MotionEvent.ACTION_POINTER_DOWN: scrollPointerId = MotionEventCompat.getPointerId(e, actionIndex); initialTouchX = Math.round(MotionEventCompat.getX(e, actionIndex) + 0.5f); initialTouchY = Math.round(MotionEventCompat.getY(e, actionIndex) + 0.5f); return super.onInterceptTouchEvent(e); case MotionEvent.ACTION_MOVE: int index = MotionEventCompat.findPointerIndex(e, scrollPointerId); if (index < 0) { return false; } int x = Math.round(MotionEventCompat.getX(e, index) + 0.5f); int y = Math.round(MotionEventCompat.getY(e, index) + 0.5f); if (getScrollState() != SCROLL_STATE_DRAGGING) { int dx = x - initialTouchX; int dy = y - initialTouchY; boolean startScroll = false; if (getLayoutManager().canScrollHorizontally() && Math.abs(dy) > touchSlop && (Math.abs(dx) > Math.abs(dy))) { startScroll = true; } if (getLayoutManager().canScrollVertically() && Math.abs(dy) > touchSlop && (Math.abs(dy) > Math.abs(dx))) { startScroll = true; } // if (getLayoutManager().canScrollVertically() && Math.abs(dy) > touchSlop && // (getLayoutManager().canScrollHorizontally() || Math.abs(dy) > Math.abs(dx))) { // startScroll = true; // } return startScroll && super.onInterceptTouchEvent(e); } return super.onInterceptTouchEvent(e); default: return super.onInterceptTouchEvent(e); } }
上面重写的onInterceptTouchEvent方法中,全部代码都是源码,惟一不一样的就是添加了咱们本身业务判断的逻辑,横向距离和纵向距离的判断,添加了startScroll这个参数的判断code
if (getLayoutManager().canScrollHorizontally() && Math.abs(dy) > touchSlop && (Math.abs(dx) > Math.abs(dy))) { startScroll = true; } if (getLayoutManager().canScrollVertically() && Math.abs(dy) > touchSlop && (Math.abs(dy) > Math.abs(dx))) { startScroll = true; }