1. 程式人生 > >【android】點選touch事件流程分析

【android】點選touch事件流程分析

1、onTouch和onTouchEvent的區別

public boolean dispatchTouchEvent(MotionEvent event) {
        if (mOnTouchListener != null && mOnTouchListener.onTouch(this, event)) {
            return true;
        }
        return onTouchEvent(event);
    }

1、如果dispatchTouchEvent返回值為true則本次事件被系統消耗掉(就是被控制元件處理了), 然後一個新的事件會被傳入(如down事件返回true,則後續的move、up等事件也將被系統傳入進行處理,否則move、up等事件不會響應)

2、如果dispatchTouchEvent返回值為false,則不會有新的事件被傳入。

3、如果onTouch() return true則代表程式碼1中將不會執行 return onTouchEvent(event);語句,這也就是說這次系統事件會被消耗掉,將會再次執行dispatchTouchEvent這個方法。

4、如果onTouch() return false則代表會執行onTouchEvent(event);這個方法,本次事件是否會被消耗掉將取決於onTouchEvent的返回值。

以上說的情況適用於View物件而不是ViewGroup物件,ViewGroup物件下次再分析

2、dispatchTouchEvent()、onInterceptTouchEvent()和onTouchEvent()

onInterceptTouchEvent()用於處理事件並改變事件的傳遞方向。返回值為false時事件會傳遞給子控制元件的onInterceptTouchEvent();
返回值為true時事件會傳遞給當前控制元件的onTouchEvent(),而不在傳遞給子控制元件,這就是所謂的Intercept(截斷)。

onTouchEvent() 用於處理事件,返回值決定當前控制元件是否消費(consume)了這個事件。

由於onInterceptTouchEvent()的機制比較複雜,上面的說明寫的也比較複雜,總結一下,基本的規則是:
1.       down事件首先會傳遞到onInterceptTouchEvent()方法
2.       如果該ViewGroup的onInterceptTouchEvent()在接收到down事件處理完成之後return false,那麼後續的move, up等事件將繼續會先傳遞給該ViewGroup,之後才和down事件一樣傳遞給最終的目標view的onTouchEvent()處理。
3.       如果該ViewGroup的onInterceptTouchEvent()在接收到down事件處理完成之後return true,那麼後續的move, up等事件將不再傳遞給onInterceptTouchEvent(),而是和down事件一樣傳遞給該ViewGroup的onTouchEvent()處理,注意,目標view將接收不到任何事件。
4.       如果最終需要處理事件的view的onTouchEvent()返回了false,那麼該事件將被傳遞至其上一層次的view的onTouchEvent()處理。
5.       如果最終需要處理事件的view 的onTouchEvent()返回了true,那麼後續事件將可以繼續傳遞給該view的onTouchEvent()處理。

onInterceptTouchEvent返回值只是決定了是要把事件傳遞給自身的onTouch事件還是傳遞給子元件的onTouch事件。返回false表示沒有消費完將傳遞個子元件的onTouch方法,返回true表示自身消費此事件,將傳遞給自身的onTouch方法而不會傳遞給子元件的onTouch方法了。

dispatchTouchEvent是處理觸控事件分發,事件(多數情況)是從Activity的dispatchTouchEvent開始的。執行

super.dispatchTouchEvent(ev),事件向下分發。

    onInterceptTouchEventViewGroup提供的方法,預設返回false,返回true表示攔截。

    onTouchEvent是View中提供的方法,ViewGroup也有這個方法,view中不提供onInterceptTouchEvent。view中預設返回true,表示消費了這個事件。

View裡,有兩個回撥函式 :

[java] view plaincopyprint?在CODE上檢視程式碼片派生到我的程式碼片
  1. publicboolean dispatchTouchEvent(MotionEvent ev);    
  2. publicboolean onTouchEvent(MotionEvent ev);   

ViewGroup裡,有三個回撥函式 :

[java] view plaincopyprint?在CODE上檢視程式碼片派生到我的程式碼片
  1. publicboolean dispatchTouchEvent(MotionEvent ev);    
  2. publicboolean onInterceptTouchEvent(MotionEvent ev);    
  3. publicboolean onTouchEvent(MotionEvent ev);  
在Activity裡,有兩個回撥函式 :
[java] view plaincopyprint?在CODE上檢視程式碼片派生到我的程式碼片
  1. publicboolean dispatchTouchEvent(MotionEvent ev);    
  2. publicboolean onTouchEvent(MotionEvent ev);    

    Android中預設情況下事件傳遞是由最終的view的接收到,傳遞過程是從父佈局到子佈局,也就是從Activity到ViewGroup到View的過程,預設情況,ViewGroup起到的是透傳作用。


    觸控事件是一連串ACTION_DOWN,ACTION_MOVE..MOVE…MOVE、最後ACTION_UP,觸控事件還有ACTION_CANCEL事件。事件都是從ACTION_DOWN開始的,Activity的dispatchTouchEvent()首先接收到ACTION_DOWN,執行super.dispatchTouchEvent(ev),事件向下分發。

    dispatchTouchEvent()返回true,後續事件(ACTION_MOVE、ACTION_UP)會再傳遞,如果返回false,dispatchTouchEvent()就接收不到ACTION_UP、ACTION_MOVE。

3、onTouchEvent,onClick,onLongClick

Android中,onClickonLongClick的觸發是和ACTION_DOWNACTION_UP相關的,在時序上,如果我們在一個View中同時覆寫了onClickonLongClickonTouchEvent的話,onTouchEvent是最先捕捉到ACTION_DOWNACTION_UP事件的,其次才可能觸發onClick或者onLongClick。可以看到,Click的觸發是在系統捕捉到ACTION_UP後發生並由performClick()執行的,performClick裡會呼叫先前註冊的監聽器的onClick()方法,而LongClick的觸發則是從ACTION_DOWN開始,由postCheckForLongClick()方法完成。從實現中可以看到onClick()onLongClick()方法是由ACTION_DOWNACTION_UP事件捕捉後根據各種情況最終確定是否觸發的,也就是說如果我們在一個Activity或者View中同時監聽或者覆寫了onClick(),onLongClick()onTouchEvent()方法,並不意味著只會發生其中一種。

要弄清楚這個問題只要理解Android對事件處理的所謂消費(consume)概念即可,一個使用者的操作會被傳遞到不同的View控制元件和同一個控制元件的不同監聽方法處理,任何一個接收並處理了該次事件的方法如果在處理完後返回了true,那麼該次event就算被完全處理了,其他的View或者監聽方法就不會再有機會處理該event了。

     onLongClick的發生是由單獨的執行緒完成的,並且在ACTION_UP之前,而onClick的發生是在ACTION_UP後,因此同一次使用者touch操作就有可能既發生onLongClick又發生onClick。這樣是不是不可思議?所以及時向系統表示“我已經完全處理(消費)了使用者的此次操作”,是很重要的事情。例如,我們如果在onLongClick()方法的最後return true,那麼onClick事件就沒有機會被觸發了。