最近師兄讓我分析下onTouchEvent和onInterceptTouchEvent的區別,在網上尋找了很多資料,但發現自己測試的結果和他們說的有不一樣的地方,當所有的onTouchEvent和onInterceptTouchEvent返回的都是false時,只有DOWN事件會按他們說的流程執行,而MOVE和UP事件則不會被響應。
測試1:
LayoutView1.onInterceptTouchEvent返回false.
LayoutView1.onTouchEvent返回false.
LayoutView2.onInterceptTouchEvent返回false.
LayoutView2.onTouchEvent返回false.
MyTextView.onTouchEvent返回false.
測試1結果:
05-16 01:54:37.742: INFO/System.out(894): LayoutView1.onInterceptTouchEvent.DOWN
05-16 01:54:37.742: INFO/System.out(894): LayoutView2.onInterceptTouchEvent.DOWN
05-16 01:54:37.742: INFO/System.out(894): MyTextView.onTouchEvent.DOWN
05-16 01:54:37.752: INFO/System.out(894): LayoutView2.onTouchEvent.DOWN
05-16 01:54:37.752: INFO/System.out(894): LayoutView1.onTouchEvent.DOWN
測試2:LayoutView1.onInterceptTouchEvent返回false.
LayoutView1.onTouchEvent返回false.
LayoutView2.onInterceptTouchEvent返回true.
LayoutView2.onTouchEvent返回false.
MyTextView.onTouchEvent返回false.
測試2結果:
05-16 01:58:17.602: INFO/System.out(923): LayoutView1.onInterceptTouchEvent.DOWN
05-16 01:58:17.622: INFO/System.out(923): LayoutView2.onInterceptTouchEvent.DOWN
05-16 01:58:17.622: INFO/System.out(923): LayoutView2.onTouchEvent.DOWN
05-16 01:58:17.622: INFO/System.out(923): LayoutView1.onTouchEvent.DOWN
經過以上測試,我認為應該在下邊轉載的文章中添加一條:
如果沒有任何視圖的onTouchEvent返回true,則UP和MOVE事件將不會被任何試圖的onInterceptTouchEvent和onTouchEvent捕捉。
轉自:http://www.javaask.com/mobile/android/2011/0419/6890.html
onInterceptTouchEvent和onTouchEvent調用時序
onInterceptTouchEvent()是ViewGroup的一個方法,目的是在系統向該ViewGroup及其各個childView觸發onTouchEvent()之前對相關事件進行一次攔截,Android這麼設計的想法也很好理解,由於ViewGroup會包含若干childView,因此需要能夠統一監控各種touch事件的機會,因此純粹的不能包含子view的控制項是沒有這個方法的,如LinearLayout就有,TextView就沒有。
onInterceptTouchEvent()使用也很簡單,如果在ViewGroup裡覆寫了該方法,那麼就可以對各種touch事件加以攔截。但是如何攔截,是否所有的touch事件都需要攔截則是比較複雜的,touch事件在onInterceptTouchEvent()和onTouchEvent以及各個childView間的傳遞機制完全取決於onInterceptTouchEvent()和onTouchEvent()的傳回值。並且,針對down事件處理的傳回值直接影響到後續move和up事件的接收和傳遞。
關於傳回值的問題,基本規則很清楚,如果return true,那麼表示該方法消費了此次事件,如果return false,那麼表示該方法並未處理完全,該事件仍然需要以某種方式傳遞下去繼續等待處理。
由於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()處理。
下面用一個簡單的實驗說明上述複雜的規則。視圖自底向上共3層,其中LayoutView1和LayoutView2就是LinearLayout, MyTextView就是TextView:
對應的xml布局檔案如下:
<?xml version="1.0" encoding="utf-8"?>
<com.touchstudy.LayoutView1 xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<com.touchstudy.LayoutView2
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center">
<com.touchstudy.MyTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tv"
android:text="AB"
android:textSize="40sp"
android:textStyle="bold"
android:background="#FFFFFF"
android:textColor="#0000FF"/>
</com.touchstudy.LayoutView2>
</com.touchstudy.LayoutView1>
下面看具體情況:
1. onInterceptTouchEvent()處理down事件均返回false,onTouchEvent()處理事件均返回true
------------------------------------------------------------------------------------------------------------------------------
04-11 03:58:42.620: DEBUG/LayoutView1(614): onInterceptTouchEvent action:ACTION_DOWN
04-11 03:58:42.620: DEBUG/LayoutView2(614): onInterceptTouchEvent action:ACTION_DOWN
04-11 03:58:42.620: DEBUG/MyTextView(614): onTouchEvent action:ACTION_DOWN
04-11 03:58:42.800: DEBUG/LayoutView1(614): onInterceptTouchEvent action:ACTION_MOVE
04-11 03:58:42.800: DEBUG/LayoutView2(614): onInterceptTouchEvent action:ACTION_MOVE
04-11 03:58:42.800: DEBUG/MyTextView(614): onTouchEvent action:ACTION_MOVE
…… //省略過多的ACTION_MOVE
04-11 03:58:43.130: DEBUG/LayoutView1(614): onInterceptTouchEvent action:ACTION_UP
04-11 03:58:43.130: DEBUG/LayoutView2(614): onInterceptTouchEvent action:ACTION_UP
04-11 03:58:43.150: DEBUG/MyTextView(614): onTouchEvent action:ACTION_UP
------------------------------------------------------------------------------------------------------------------------------
這是最常見的情況,onInterceptTouchEvent並沒有做任何改變事件傳遞時序的操作,效果上和沒有覆寫該方法是一樣的。可以看到,各種事件的傳遞本身是自底向上的,次序是:LayoutView1->LayoutView2->MyTextView。注意,在onInterceptTouchEvent均返回false時,LayoutView1和LayoutView2的onTouchEvent並不會收到事件,而是最終傳遞給了MyTextView。
2. LayoutView1的onInterceptTouchEvent()處理down事件返回true,
MyTextView的onTouchEvent()處理事件返回true
------------------------------------------------------------------------------------------------------------------------------
04-11 03:09:27.589: DEBUG/LayoutView1(446): onInterceptTouchEvent action:ACTION_DOWN
04-11 03:09:27.589: DEBUG/LayoutView1(446): onTouchEvent action:ACTION_DOWN
04-11 03:09:27.629: DEBUG/LayoutView1(446): onTouchEvent action:ACTION_MOVE
04-11 03:09:27.689: DEBUG/LayoutView1(446): onTouchEvent action:ACTION_MOVE
…… //省略過多的ACTION_MOVE
04-11 03:09:27.959: DEBUG/LayoutView1(446): onTouchEvent action:ACTION_UP
------------------------------------------------------------------------------------------------------------------------------
從Log可以看到,由於LayoutView1在攔截第一次down事件時return true,所以後續的事件(包括第一次的down)將由LayoutView1本身處理,事件不再傳遞下去。
3. LayoutView1,LayoutView2的onInterceptTouchEvent()處理down事件返回false,
MyTextView的onTouchEvent()處理事件返回false
LayoutView2的onTouchEvent()處理事件返回true
----------------------------------------------------------------------------------------------------------------------------
04-11 09:50:21.147: DEBUG/LayoutView1(301): onInterceptTouchEvent action:ACTION_DOWN
04-11 09:50:21.147: DEBUG/LayoutView2(301): onInterceptTouchEvent action:ACTION_DOWN
04-11 09:50:21.147: DEBUG/MyTextView(301): onTouchEvent action:ACTION_DOWN
04-11 09:50:21.147: DEBUG/LayoutView2(301): onTouchEvent action:ACTION_DOWN
04-11 09:50:21.176: DEBUG/LayoutView1(301): onInterceptTouchEvent action:ACTION_MOVE
04-11 09:50:21.176: DEBUG/LayoutView2(301): onTouchEvent action:ACTION_MOVE
04-11 09:50:21.206: DEBUG/LayoutView1(301): onInterceptTouchEvent action:ACTION_MOVE
04-11 09:50:21.217: DEBUG/LayoutView2(301): onTouchEvent action:ACTION_MOVE
…… //省略過多的ACTION_MOVE
04-11 09:50:21.486: DEBUG/LayoutView1(301): onInterceptTouchEvent action:ACTION_UP
04-11 09:50:21.486: DEBUG/LayoutView2(301): onTouchEvent action:ACTION_UP
----------------------------------------------------------------------------------------------------------------------------
可以看到,由於MyTextView在onTouchEvent()中return false,down事件被傳遞給其父view,即LayoutView2的onTouchEvent()方法處理,由於在LayoutView2的onTouchEvent()中return true,所以down事件傳遞並沒有上傳到LayoutView1。注意,後續的move和up事件均被傳遞給LayoutView2的onTouchEvent()處理,而沒有傳遞給MyTextView。