Touch事件傳遞機制解析
涉及的知識點:
主要涉及的方法:
方法 | 用途 |
---|---|
public boolean dispatchTouchEvent(MotionEvent ev) | 用來分發TouchEvent |
public boolean onInterceptTouchEvent(MotionEvent ev) | 用來攔截TouchEvent |
public boolean onTouchEvent(MotionEvent ev) | 用來處理TouchEvent |
擁有這三個方法的類:
型別 | 相關類 | 方法 |
---|---|---|
Activity類 | Activity | dispatchTouchEvent(); onTouchEvent(); |
View容器(ViewGroup的子類) | FrameLayout、LinearLayou、ListView、ScrollVIew… | dispatchTouchEvent(); onInterceptTouchEvent(); onTouchEvent(); |
View控制元件(非ViewGroup子類) | Button、TextView、EditText…… | dispatchTouchEvent(); onTouchEvent(); |
ViewGroup的dispatchTouchEvent是真正在執行“分發”工作,而View的dispatchTouchEvent方法,並不執行分發工作,或者說它分發的物件就是自己,決定是否把touch事件交給自己處理,而處理的方法,便是onTouchEvent事件
三個方法的具體作用:
方法 | 用途 |
---|---|
dispatchTouchEvent() | 用來分派事件。其中呼叫了onInterceptTouchEvent()和onTouchEvent(),一般不重寫該方法 |
onInterceptTouchEvent() | 用來攔截事件。ViewGroup預設為(return false)表示不對事件進行攔截,事件將向下傳遞(傳遞給其子View);若手動重寫該方法,使其返回true則表示攔截,事件將終止向下傳遞,則事件將由當前ViewGroup類(onTouchEvent)來處理 |
onTouchEvent() | 用來處理事件。返回true則表示該View能處理該事件,事件將終止向上傳遞(傳遞給其父View);返回false表示不能處理,則把事件傳遞給其父View的onTouchEvent()方法來處理 |
三個方法並不總是同時存在的
無攔截的touch事件處理過程
流程圖
(檢視巢狀關係 Activity–>out–>middle–>center,點選center)
分析
分發過程中,所有元件都不會處理事件,且事件並不會被center的onTouchEvent方法“消費”(ruturn false),則事件會層層逆向傳遞迴到Activity。對於後續的move、up事件,由於第一個down事件已經確定由Activity處理事件,故up事件由Activity的dispatchTouchEvent直接分發給自己的onTouchEvent方法處理。
即,onInterceptTouchEvent()來決定是否將事件傳遞給子View處理,onTouchEvent()用來對具體事件的處理(對一些功能的實現)並且決定了是否將處理事件的能力返回給父View.
例項分析
一次點選(擡起)操作,當前的activity分別會響應一次ActionDown,n次ActionMove(n>=0),1次ActionUp事件
Demo示圖
例. 檢視巢狀 Activity–>ViewA–>ViewB–>ViewC(其中ViewA、ViewB繼承至FrameLayout,ViewC繼承自View)
情況一(點選ViewC,過程中無任何攔截)
(注:logout中的Main表示Activity)
情況二(點選ViewC,過程中存在攔截操作)
點選ViewC, 只在ViewA中對事件下發過程進行攔截onInterceptTouchEvent{…..return true;},並且ViewA中的onTouchEvent不處理事件(return false),事件回傳
情況三(點選ViewB, 對事件回傳過程進行截獲)
只在ViewA中對事件回傳過程進行截獲onTouchEvent{…..return true;}
(ActionDown結束後,後續的事件(Move、Up)傳遞過程中,只有被確定處理該touch事件的view才進行onTouchEvent方法的響應)
說明:一次完整的Touch事件,應該是由一個Down、一個Up和若干個Move組成的。Down方式通過dispatchTouchEvent分發,分發的目的是為了找到真正需要處理完整Touch請求的View。當某個View或者ViewGroup的onTouchEvent事件返回true時,便表示它是真正要處理這次請求的View,之後的Aciton_UP和Action_MOVE將由它處理。當所有子View的onTouchEvent都返回false時,這次的Touch請求就由根ViewGroup,即Activity自己處理了。
情況四(點選ViewC, 對事件分發過程進行攔截):
在ViewB中對事件分發過程進行攔截dispatchTouchEvent{…..return true;}