現在我們有豎向滑動的RecyclerView,在每個item內部又嵌套了一個橫向滑動的RecyclerView,那麼我們手指在滑動RecyclerVIew時,到底是豎向的響應還是橫向的響應呢?
如圖:紅色線爲手指滑動距離,右上方滑動到左下方;綠色爲豎向滑動距離;藍色爲橫向滑動距離;我們的期望是如果手指滑動的橫向距離大於豎向距離的話就響應豎向的外層RecyclerVIew的滑動;如果手指移動的豎向距離大於橫向距離,則滑動內部的橫向的RecyclerView。
整體效果如下,完整項目:https://github.com/buder-cp/CustomView/tree/master/buder_DN_view/buderdn14
我們繼承RecyclerView,重寫其中的onInterceptTouchEvent方法,根據我們需要的業務邏輯去實現事件攔截:
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這個參數的判斷
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;
}