在View 中的dispatchTouchEvent,OnInterceptTouchEvent ,OnTouchEvent方法 這篇文章中介紹了一下dispatchTouchEvent,OnInterceptTouchEvent ,OnTouchEvent三個方法。今天想分析一下觸摸事件分發和處理機制。
爲了能夠清楚的分析,我們先新建一個項目,佈局如圖:
ViewGroup1嵌套ViewGroup2,然後在嵌套CustomView(這裏我繼承自TextView)。佈局很簡單,只是爲了說明ViewGroup的分發過程。
然後在相應的View中重寫dispatchTouchEvent,OnInterceptTouchEvent ,OnTouchEvent方法(CustomView沒有OnInterceptTouchEvent),並在每個方法中輸出相應的Log:
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.e("ViewGroup1","ViewGroup1 dispatchTouchEvent");
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.e("ViewGroup1","ViewGroup1 onInterceptTouchEvent");
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.e("ViewGroup1","ViewGroup1 onTouchEvent");
return super.onTouchEvent(event);
}
CustomView中:
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
Log.e("CustomView", "CustomView dispatchTouchEvent");
return super.dispatchTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.e("CustomView", "CustomView onTouchEvent");
return super.onTouchEvent(event);
}
運行程序,點擊CustomView會得到如下Log信息:
E/ViewGroup1: ViewGroup1 dispatchTouchEvent
E/ViewGroup1: ViewGroup1 onInterceptTouchEvent
E/ViewGroup2: ViewGroup2 dispatchTouchEvent
E/ViewGroup2: ViewGroup2 onInterceptTouchEvent
E/CustomView: CustomView dispatchTouchEvent
E/CustomView: CustomView onTouchEvent
E/ViewGroup2: ViewGroup2 onTouchEvent
E/ViewGroup1: ViewGroup1 onTouchEvent
從Log信息可以看出,首先會先執行ViewGroup1 dispatchTouchEvent方法,然後在View 中的dispatchTouchEvent,OnInterceptTouchEvent ,OnTouchEvent方法 中我們講過dispatchTouchEvent()方法的內部邏輯:
public boolean dispatchTouchEvent(Motion e){
boolean result=false;
if(onInterceptTouchEvent(e)){
//如果當前View截獲事件,那麼事件就會由當前View處理,即調用onTouchEvent()
result=onTouchEvent(e);
}else{
//如果不截獲那麼交給其子View來分發
result=child.dispatchTouchEvent(e);
}
return result;
}
在ViewGroup1 dispatchTouchEvent方法調用後,接着會調用onInterceptTouchEvent()來判斷是否需要截取事件,默認是不截取的。事件會傳遞到ViewGroup1的子View也就是ViewGroup2。即ViewGroup2 的dispatchTouchEvent方法被調用,直到CustomView。當事件傳遞到CustomView後,同樣是CustomView的dispatchTouchEvent方法會執行。可以看出,整個事件的分發是從ViewGroup1向CustomView傳遞的。此時如果CustomView 不能處理改事件,也就是說CustomView的OnTouchView方法返回爲false,那麼事件會向上交給ViewGroup2的OnTouchEvent()事件處理,以此類推:
如果ViewGroup2的onInterceptTouchEvent()返回爲true,即要攔截事件,又會出現什麼情況呢?
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.e("ViewGroup2","ViewGroup2 onInterceptTouchEvent");
return true;
}
運行結果:
E/ViewGroup1: ViewGroup1 dispatchTouchEvent
E/ViewGroup1: ViewGroup1 onInterceptTouchEvent
E/ViewGroup2: ViewGroup2 dispatchTouchEvent
E/ViewGroup2: ViewGroup2 onInterceptTouchEvent
E/ViewGroup2: ViewGroup2 onTouchEvent
E/ViewGroup1: ViewGroup1 onTouchEvent
CustomView的dispatchTouchEvent()沒有執行,事件沒有傳遞給CustomView,而是直接調用了ViewGroup2的ViewGroup2 的onTouchEvent。
其實這也是很好理解的,和我們日常生活中辦事流程是一樣的,公司老闆(ViewGroup1)把任務交給經理(ViewGroup2),經理在把工作交給員工(CustomView)。這裏如果經理(ViewGroup2)覺得這件事自己可以完成就截獲這個工作(onInterceptTouchEvent返回爲true),就不會再將任務分配給員工(CustomView)處理了。
說完分發流程,現在來看看事件的響應機制,我們將事件傳遞到CustomView,並且將CustomView的OnTouchEvent事件返回爲true,得到以下結果:
E/ViewGroup1: ViewGroup1 dispatchTouchEvent
E/ViewGroup1: ViewGroup1 onInterceptTouchEvent
E/ViewGroup2: ViewGroup2 dispatchTouchEvent
E/ViewGroup2: ViewGroup2 onInterceptTouchEvent
E/CustomView: CustomView dispatchTouchEvent
E/CustomView: CustomView onTouchEvent
我們會發現ViewGroup2 的OnTouchEvent不會在執行了,還是用我們剛剛的例子來說,就是員工(CustomView)在接到任務後順利的完成了任務,就不必在勞煩上司響應處理了。只有在員工(CustomView)無法完成這項工作時(OnTouchEvent返回爲false)時纔會請求經理幫忙(ViewGroup2 調用OnTouchEvent方法),同樣的,如果經理也不能搞定的話,就交給老闆了。
如果有興趣的話,可以去研究研究源碼:
推薦:
Android事件分發機制完全解析,帶你從源碼的角度徹底理解(上)
第21天 Android Touch事件學習 8 事件分發原理