TouchEvent
TouchEvent 分三種事件:down、move、up。
其中move事件在一個操作中(這里說的一個操作就是用戶與屏幕的交互,即由down到up的動作序列)可能會發生多次。
但是,我們認為一個動作序列會包含以上三種事件,因此,在事件處理中就是要處理好這個過程,而最重要的就是down事件,這是一個動作序列的起始,沒有down談不上后面的事件了。
所以,我們把消耗down事件的類當做是這個動作序列的最終載體。
如果Down事件不歸你處理,那這個動作序列的move,up也不歸你處理。
他們的觸發順序會是這樣:
ACTION_DOWN->ACTION_MOVE->ACTION_MOVE->ACTION_MOVE...->ACTION_MOVE->ACTION_UP
Touch事件傳遞的相關方法
android系統中的幾乎所有View的子類都具有下面三個和TouchEvent處理密切相關的方法:
//這個方法用來分發TouchEvent public boolean dispatchTouchEvent(MotionEvent ev) //這個方法用來攔截TouchEvent //只有ViewGroup包含此方法,普通view不包含方法 public boolean onInterceptTouchEvent(MotionEvent ev) //這個方法用來處理TouchEvent public boolean onTouchEvent(MotionEvent ev)
onTouchEvent、onTouch
OnTouchListener接口是用來處理手機屏幕事件的監聽接口,需要實現該接口的onTouch事件/OnClick事件來設置觸發事件,然后我們可以通過setOnTouchListener()為任何需要的View的子類添加該監聽器。
那么OnTouchListener接口中的onTouch方法 和 Touch事件的傳遞有什么關系呢?
在onTouchEvent的源碼中有這樣一段:
if (li != null && li.mOnClickListener != null) { playSoundEffect(SoundEffectConstants.CLICK); li.mOnClickListener.onClick(this);
return true; }
若我們又注冊了onClick監聽,則在onTouchEvent中就會執行該監聽,同時返回true。
若沒有注冊onClick監聽,頂層view的onTouchEvent默認返回false,其他層view的onTouchEvent默認返回true。
因此,如果onTouch返回了true,則事件被消費掉,就不再執行onTouchEvent了,更別說onClick監聽了。如果onTouch返回false,那么會繼續執行onTouchEvent,再執行onClick監聽,若onTouchEvent中返回了true,則事件被消費掉,不再往下層view傳遞。
結論:onTouchListener的onTouch方法優先級比onTouchEvent高,會先觸發。假若onTouchListener中的onTouch方法返回true,表示此次事件已經被消費了,那onTouchEvent是接收不到消息的。假如onTouch方法返回false,會接着觸發onTouchEvent,反之onTouchEvent方法不會被調用。內置諸如click事件的實現等等都基於onTouchEvent,假如onTouch返回true,這些事件將不會被觸發。
Touch事件傳遞簡易的流程圖:
結合圖來看過程:
如果返回值是 Super.dispatchTouchEvent ,意味着由onInterceptTouchEvent決定事件流向。
如果調用了Super.dispatchTouchEvent。 這樣就會繼續調用onInterceptTouchEvent事件。因此如果需要多個控件同時處理,則一定需要返回true,並調用Super.dispatchTouchEvent
也就是說想要把事件傳遞給子view,則Super.dispatchTouchEvent 是必不可少的。
任何view的onTouch或者onTouchEvent方法返回了true,則表示該事件就已經到此被消費掉了,不再往下傳遞。
其他:
- Down事件在onInterceptTouchEvent()后返回true,則傳遞到onTouchEvent,當其返回true時,本次動作序列的后續事件不會再通過onInterceptTouchEvent了,而是在dispatchTouchEvent中直接傳遞於onTouchEvent。也就是說后續事件直接默認被該view的dispatchTouchEvent分發至onTouchEvent。
- Down事件在onTouchEvent后返回false后導致本次事件沒有被消費掉,則向上傳遞到父view的onTouchEvent,若返回true,則后續的move、up事件直接由父view的dispatchTouchEvent傳遞給自己的onTouchEvent,而不經過父view的onInterceptTouchEvent,后面的子view自然接收不到Touch事件。
- onInterceptTouchEvent默認返回false,頂層view的onTouchEvent默認返回false,其他view的onTouchEvent默認返回true。
- 如果我們在一個View中同時覆寫了onClick、onLongClick及onTouchEvent的話,onTouchEvent是最先捕捉到ACTION_DOWN和ACTION_UP事件的,其次才可能觸發onClick或者onLongClick。
GestureDetector手勢識別類
通過重寫View.OnTouchListener接口的onTouch(View v, MotionEvent event)方法,我們可以處理一些簡單的touch事件,但是這個方法並不能識別手勢,如果需要處理一些復雜的手勢,用這個接口就會很麻煩(因為我們要自己根據用戶觸摸的軌跡去判斷是什么手勢)。好在Android為我們提供了GestureDetector類,通過它,我們可以輕松的進行手勢識別。
為View和Activity加入手勢操作的步驟如下:
1、為View或者Activity實現OnGestureListener接口,覆寫需要的手勢的回調方法。
2、創建一個GestureDetector對象mygesturedetector,設置其監聽器。
3、覆寫View或者Activity的OnTouchEvent方法,調用或返回mygesturedetector.onTouchEvent(ev),將事件交給mygesturedetector處理。
非常好的參考資料:
http://www.cnblogs.com/ghj1976/archive/2012/04/13/2445561.html 消息分發知識基礎
http://ipjmc.iteye.com/blog/1694146 Android事件處理
http://www.longdw.com/touchevent-android/ Android的ViewGroup中事件的傳遞機制