當我們内外兩層View都可以滑動時候,就會産生滑動沖突!
- 1.外層與内層滑動方向不一緻,外層ViewGroup是可以橫向滑動的,内層View是可以豎向滑動的(類似ViewPager,每個頁面裡面是ListView)
- 2.外層與内層滑動方向一緻,外層ViewGroup是可以豎向滑動的,内層View同樣也是豎向滑動的(類似ScrollView包裹ListView)
注: 一場景有外部處理和内部處理兩種發誓,二場景主要看邏輯實作
解決方案有兩種,外部處理和内部處理
外部攔截法:
// 外層view 的 onInterceptTouchEvent
private int mLastX;
private int mLastY;
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean intercepted = false;
int x = (int) ev.getX();
int y = (int) ev.getY();
final int action = ev.getAction() & MotionEvent.ACTION_MASK;
switch (action) {
case MotionEvent.ACTION_DOWN:
intercepted = false;
//調用ViewPager的onInterceptTouchEvent方法初始化mActivePointerId
super.onInterceptTouchEvent(ev);
break;
case MotionEvent.ACTION_MOVE:
//橫坐标位移增量
int deltaX = x - mLastXIntercept;
//縱坐标位移增量
int deltaY = y - mLastYIntercept;
if (Math.abs(deltaX)>Math.abs(deltaY)){
intercepted = true;
}else{
intercepted = false;
}
break;
case MotionEvent.ACTION_UP:
intercepted = false;
break;
default:
break;
}
mLastXIntercept = x;
mLastYIntercept = y;
LogUtil.e(TAG,"intercepted = "+intercepted);
return intercepted;
}
Math.abs(deltaX)>Math.abs(deltaY)表示橫向位移增量大于豎向位移增量,即水準滑動,則攔截事件。
注意:
- ACTION_DOWN 一定傳回false,不要攔截它,否則根據View事件分發機制,後續ACTION_MOVE 與 ACTION_UP事件都将預設交給父View去處理!
- 原則上ACTION_UP也需要傳回false,如果傳回true,并且滑動事件交給子View處理,那麼子View将接收不到ACTION_UP事件,子View的onClick事件也無法觸發。而父View不一樣,如果父View在ACTION_MOVE中開始攔截事件,那麼後續ACTION_UP也将預設交給父View處理!
private int mLastX;
private int mLastY;
// 内層view 的 onInterceptTouchEvent
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
int x = (int) ev.getX();
int y = (int) ev.getY();
final int action = ev.getAction() & MotionEvent.ACTION_MASK;
switch (action) {
case MotionEvent.ACTION_DOWN:
getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_MOVE:
//水準移動的增量
int deltaX = x - mLastX;
//豎直移動的增量
int deltaY = y - mLastY;
//當水準增量大于豎直增量時,表示水準滑動,此時需要父View去處理事件
if (Math.abs(deltaX) > Math.abs(deltaY)){
getParent().requestDisallowInterceptTouchEvent(false);
}
break;
case MotionEvent.ACTION_UP:
break;
default:
break;
}
mLastX = x;
mLastY = y;
return super.dispatchTouchEvent(ev);
}
// 外層view 的 onInterceptTouchEvent
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final int action = ev.getAction() & MotionEvent.ACTION_MASK;
if (action == MotionEvent.ACTION_DOWN){
super.onInterceptTouchEvent(ev);
return false;
}
return true;
}