Android中Touch事件傳遞總結


 

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事件傳遞簡易的流程圖:

繪圖1

 

結合圖來看過程:

如果返回值是 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中事件的傳遞機制

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM