對于滑動沖突,相信安卓開發(fā)的人都會有這種體會:本來從網(wǎng)上下載的demo運行得好好的,但是只要出現(xiàn)滑動沖突,demo就無法正常工作了。許多開發(fā)者面對滑動沖突都會顯得束手無策,(包括小編)于是小編就趕緊到處學習方法,并整理了下面的滑動沖突類型及解決方法,希望對和小編一樣的初學者有幫助。
常見的沖突場景
- 場景一:外部滑動方向和內(nèi)部滑動方向不一致

在主流應用中,幾乎都會出現(xiàn)這種效果:首頁可以通過左右滑動來切換頁面,而每個頁面內(nèi)部往往又是一個ListView,這種情形下是有滑動沖突的(但是ViewPager內(nèi)部處理了這種滑動沖突)
處理規(guī)則
—— 根據(jù)用戶滑動的方向決定讓內(nèi)部View還是外部View攔截點擊事件
- 場景二:外部滑動方向和內(nèi)部滑動方向一致

在這類場景里,可以想象父View可以通過上下滑動切換頁面,然而內(nèi)部還是一個ListView,當用戶滑動的時候系統(tǒng)不知道該將滑動事件分發(fā)給誰
處理規(guī)則
—— 根據(jù)業(yè)務的規(guī)定決定讓內(nèi)部View還是外部View攔截點擊事件
比如說上述例子,可以采用內(nèi)部攔截法,優(yōu)先將滑動事件交給內(nèi)部ListView處理,當ListView已經(jīng)到達頂部或者底部已經(jīng)無法再進行同方向的滑動時,就將滑動事件交回給外部View處理,實現(xiàn)換頁功能。
- 場景三:上面兩種情況的嵌套

這類場景也很常見,假如你的首頁是一個ViewPager,可以來回切換不同頁面,每個頁面中又有各自的ListView,然后其實還隱藏著一個SlidingMenu在左側(cè)。
處理規(guī)則
—— 根據(jù)業(yè)務的規(guī)定決定讓內(nèi)部View還是外部View攔截點擊事件
主要是最SlidingMenu的處理,業(yè)務上可以要求當用戶的向右滑動是從app最左側(cè)邊緣開始時才將事件交給SlidingMenu處理。其他部分可以跟第一個場景一樣。
常用解決方式
- 外部攔截法 —— 點擊事件都先經(jīng)過父容器的攔截處理,如果父容器需要此事件就攔截,如果不需要此事件就不攔截。
外部攔截需要重寫父容器的onInterceptTouchEvent方法,偽代碼如下:
public boolean onInterceptTouchEvent(MotionEvent event){
boolean intercepted = false;
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:{
// 對于ACTION_DOWN這個事件,父容器必須返回false,因為父容 器一旦攔截了
// ACTION_DOWN,后續(xù)的ACTION_MOVE和ACTION_UP也都會直接交由父容器處理
intercepted = false;
break;
}
case MotionEvent.ACTION_MOVE:{
if (父容器需要當前點擊事件) {
intercepted = true;
} else {
intercepted = false;
}
break;
}
case MotionEvent.ACTION_UP:{
intercepted = false;
break;
}
default:
break;
}
mLastXIntercept = x;
mLastYIntercept = y;
return intercepted;
}
- 內(nèi)部攔截法 —— 指父容器不攔截任何事件,所有的事件都傳遞給子元素,如果子元素需要此事件就直接消耗掉,否則就交由父容器進行處理。
內(nèi)部攔截需要重寫子元素的dispatchTouchEvent方法,偽代碼如下:
public boolean dispatchTouchEvent(MotionEvent event){
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:{
parent.requestDisallowInterceptTouchEvent(true);
break;
}
case MotionEvent.ACTION_MOVE:{
int deltaX = x - mLastX;
int deltxY = y - mLastY;
if (父容器需要當前點擊事件) {
parent.requestDisallowInterceptTouchEvent(false);
}
break;
}
case MotionEvent.ACTION_UP:{
break;
}
default:
break;
}
mLastX = x;
mLastY = y;
return super.dispatchTouchEvent(event);
}
另外,父容器也要做如下修改:
public boolean onInterceptTouchEvent(MotionEvent event){
int action = event.getAction();
if (action == MotionEvent.ACTION_DOWN) {
return false;
} else {
return true;
}
}