Android-onInterceptTouchEvent()和onTouchEvent()

老實說,這兩個小東東實在是太麻煩了,很很差懂,我本身那api文檔都頭暈,在網上找到不少資料,才知道是怎麼回事,這裏總結一下,記住這個原則就會很清楚了:android

一、onInterceptTouchEvent()是用於處理事件(相似於預處理,固然也能夠不處理)並改變事件的傳遞方向,也就是決定是否容許Touch事件繼續向下(子控件)傳遞,一但返回True(表明事件在當前的viewGroup中會被處理),則向下傳遞之路被截斷(全部子控件將沒有機會參與Touch事件),同時把事件傳遞給當前的控件的onTouchEvent()處理;返回false,則把事件交給子控件的onInterceptTouchEvent()後端


二、onTouchEvent()用於處理事件,返回值決定當前控件是否消費(consume)了這個事件,也就是說在當前控件在處理完Touch事件後,是否還容許Touch事件繼續向上(父控件)傳遞,一但返回True,則父控件不用操心本身來處理Touch事件。返回true,則向上傳遞給父控件(注:可能你會以爲是否消費了有關係嗎,反正我已經針對事件編寫了處理代碼?答案是有區別!好比ACTION_MOVE或者ACTION_UP發生的前提是必定曾經發生了ACTION_DOWN,若是你沒有消費ACTION_DOWN,那麼系統會認爲ACTION_DOWN沒有發生過,因此ACTION_MOVE或者ACTION_UP就不能被捕獲。)api



概念介紹

一、onInterceptTouchEvent()是用於處理事件(重點onInterceptTouchEvent這個事件是從父控件開始往子控件傳的,直到有攔截或者到沒有這個事件的view,而後就往回從子到父控件,此次是onTouch的)(相似於預處理,固然也能夠不處理)並改變事件的傳遞方向,也就是決定是否容許Touch事件繼續向下(子控件)傳遞,一但返回True(表明事件在當前的viewGroup中會被處理),則向下傳遞之路被截斷(全部子控件將沒有機會參與Touch事件),同時把事件傳遞給當前的控件的onTouchEvent()處理;返回false,則把事件交給子控件的onInterceptTouchEvent()函數

 

二、onTouchEvent()用於處理事件(重點onTouch這個事件是從子控件回傳到父控件的,一層層向下傳),返回值決定當前控件是否消費(consume)了這個事件,也就是說在當前控件在處理完Touch事件後,是否還容許Touch事件繼續向上(父控件)傳遞。返回false,則向上傳遞給父控件,詳細一點就是這個touch事件就給了父控件,那麼後面的up事件就是到這裏touch觸發,不會在傳給它的子控件。若是父控件依然是false,那touch的處理就給到父控件的父控件,那麼up的事件處理都在父控件的父控件,不會觸發下面的。佈局

返回true,若是是子控件返回true,那麼它的touch事件都在這裏處理,父控件是處理不了,由於它收不到子控件傳給他的touch,被子控件給攔截了。(這裏囉嗦了這麼多就是爲了加深記憶,這個兩個事件理解起來都這麼麻煩了,更況且去記,記我確定是一會兒就忘的了^0^)spa

(注:可能你會以爲是否消費了有關係嗎,反正我已經針對事件編寫了處理代碼?答案是有區別!好比ACTION_MOVE或者ACTION_UP發生的前提是必定曾經發生了ACTION_DOWN,若是你沒有消費ACTION_DOWN,那麼系統會認爲ACTION_DOWN沒有發生過,因此ACTION_MOVE或者ACTION_UP就不能被捕獲。)設計

詳細介紹

onInterceptTouchEvent()是ViewGroup的一個方法,目的是在系統向該ViewGroup及其各個childView觸發onTouchEvent()以前對相關事件進行一次攔截,Android這麼設計的想法也很好理解,因爲ViewGroup會包含若干childView,所以須要可以統一監控各類touch事件的機會,所以純粹的不能包含子view的控件是沒有這個方法的,如LinearLayout就有,TextView就沒有。code

onInterceptTouchEvent()使用也很簡單,若是在ViewGroup裏覆寫了該方法,那麼就能夠對各類touch事件加以攔截。可是如何攔截,是否全部的touch事件都須要攔截則是比較複雜的,touch事件在onInterceptTouchEvent()和onTouchEvent以及各個childView間的傳遞機制徹底取決於onInterceptTouchEvent()和onTouchEvent()的返回值。而且,針對down事件處理的返回值直接影響到後續move和up事件的接收和傳遞。orm

關於返回值的問題,基本規則很清楚,若是return true,那麼表示該方法消費了這次事件,若是return false,那麼表示該方法並未處理徹底,該事件仍然須要以某種方式傳遞下去繼續等待處理。xml


onInterceptTouchEvent()是ViewGroup的一個方法,目的是在系統向該ViewGroup及其各個childView觸發onTouchEvent()以前對相關事件進行一次攔截.

  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()處理。


    僅僅看這個官方文檔解釋,就能理解清楚這兩個函數關係以及用途的絕對是富有經驗的framework高手。
    不然,必定須要一個案例來闡釋。假設咱們有這樣一個layout,很是典型的


    用一個示例圖來解釋這個layout:


    一般外圍的layoutview1,layoutview2,只是佈局的容器不須要響應觸屏的點擊事件,僅僅Mytextview須要相應點擊。但這只是通常狀況,一些特殊的佈局可能外圍容器也要響應,甚至不讓裏面的mytextview去響應。更有特殊的狀況是,動態更換響應對象。
    那麼首先看一下默認的觸屏事件的在兩個函數之間的傳遞流程。以下圖:


    若是僅僅想讓MyTextView來響應觸屏事件,讓MyTextView的OnTouchEvent返回true,那麼事件流就變成以下圖,能夠看到layoutview1,layoutview2已經不能進入OnTouchEvent:


    另一種狀況,就是外圍容器想獨自處理觸屏事件,那麼就應該在相應的onInterceptTouchEvent函數中返回true,表示要截獲觸屏事件,好比layoutview1做截獲處理,處理流變成以下圖:


    以此類推,咱們能夠獲得各類具體的狀況,整個layout的view類層次中都有機會截獲,並且能看出來外圍的容器view具備優先截獲權。

    當咱們去作一些相對來說具備更復雜的觸屏交互效果的應用時候,常常須要動態變動touch event的處理對象,好比launcher待機桌面和主菜單(見下圖),從滑動屏幕開始到中止滑動過程中,只有外圍的容器view才能夠處理touch event,不然就會誤點擊上面的應用圖標或者widget.反之在靜止不動的狀態下則須要可以響應圖標(子view)的touch事件。摘取framework中abslistview代碼以下




    總結:

    僅僅經過概覽性的官方文檔是很難理解onInterceptTouchEvent函數的用途的,只有經過演繹這個抽象的規則,配以圖文才能獲取這個重要的知識。很顯然,默認是返回false,不作截獲。返回true以後,事件流的後端控件就沒有機會處理touch事件了,把默認的事件流中每一個處理函數看做一個節點,這個節點只要返回true, 後續的事件就被截止了,這樣想就很好理解。




    onInterceptTouchEvent是在ViewGroup裏面定義的。Android中的layout佈局類通常都是繼承此類的。onInterceptTouchEvent是用於攔截手勢事件的,每一個手勢事件都會先調用onInterceptTouchEvent。 
    onInterceptTouchEvent()用於處理事件並改變事件的傳遞方向。返回值爲false時事件會傳遞給子控件的onInterceptTouchEvent();返回值爲true時事件會傳遞給當前控件的onTouchEvent(),而不在傳遞給子控件,這就是所謂的Intercept(截斷)。
    onTouchEvent() 用於處理事件,返回值決定當前控件是否消費(consume)了這個事件。可能你要問是否消費了又區別嗎,反正我已經針對事件編寫了處理代碼?答案是有區別!好比ACTION_MOVE或者ACTION_UP發生的前提是必定曾經發生了ACTION_DOWN,若是你沒有消費ACTION_DOWN,那麼系統會認爲ACTION_DOWN沒有發生過,因此ACTION_MOVE或者ACTION_UP就不能被捕獲。

    1. public boolean onInterceptTouchEvent(MotionEvent ev) {

    2.         int action = ev.getAction();


    3.         switch (action & MotionEvent.ACTION_MASK) {

    4.         case MotionEvent.ACTION_DOWN: {

    5.  

    6.             if (touchMode == TOUCH_MODE_FLING) {

    7.                 return true;  //fling狀態,截獲touch,由於在滑動狀態,不讓子view處理

    8.             }

    9.             break;

    10.         }


    11.         case MotionEvent.ACTION_MOVE: {

    12.             switch (mTouchMode) {

    13.             case TOUCH_MODE_DOWN:

    14.                 final int pointerIndex = ev.findPointerIndex(mActivePointerId);

    15.                 final int y = (int) ev.getY(pointerIndex);

    16.                 if (startScrollIfNeeded(y - mMotionY)) {

    17.                     return true;//開始滑動狀態,截獲touch事件,不讓子view處理

    18.                 }

    19.                 break;

    20.             }

    21.             break;

    22.         }

    23. }

    24. <com.test.LayoutView1 xmlns:android="http://schemas.android.com/apk/res/android"  

    25.     android:orientation="vertical" android:layout_width="fill_parent"  

    26.     android:layout_height="fill_parent">  

    27.     <com.test.LayoutView2  

    28.         android:orientation="vertical" android:layout_width="fill_parent"  

    29.         android:layout_height="fill_parent" android:gravity="center">  

    30.         <com.test.MyTextView  

    31.             android:layout_width="wrap_content"   android:layout_height="wrap_content"  

    32.       />  

    33.     </com.test.LayoutView2>  

    34. </com.test.LayoutView1>



    ViewGroup裏的onInterceptTouchEvent默認值是false這樣才能把事件傳給View裏的onTouchEvent.

    ViewGroup裏的onTouchEvent默認值是false。

    View裏的onTouchEvent返回默認值是true.這樣才能執行屢次touch事件。

    相關文章
    相關標籤/搜索