如果看了下面的文章有部分你覺得熟悉,那不用想了,我是截取過來的^0^,然後補上一些細節問題,理解更方便。(說明:下面是抄襲網上兩遍文章組合成的,自己只是加了點點改動)
概念介紹
1、onInterceptTouchEvent()是用於處理事件(重點onInterceptTouchEvent這個事件是從父控制項開始往子控制項傳的,直到有攔截或者到沒有這個事件的view,然後就往回從子到父控制項,這次是onTouch的)(類似於預先處理,當然也可以不處理)並改變事件的傳遞方向,也就是決定是否允許Touch事件繼續向下(子控制項)傳遞,一但返回True(代表事件在當前的viewGroup中會被處理),則向下傳遞之路被截斷(所有子控制項將沒有機會參與Touch事件),同時把事件傳遞給當前的控制項的onTouchEvent()處理;返回false,則把事件交給子控制項的onInterceptTouchEvent()
2、onTouchEvent()用於處理事件(重點onTouch這個事件是從子控制項回傳到父控制項的,一層層向下傳),傳回值決定當前控制項是否消費(consume)了這個事件,也就是說在當前控制項在處理完Touch事件後,是否還允許Touch事件繼續向上(父控制項)傳遞。返回false,則向上傳遞給父控制項,詳細一點就是這個touch事件就給了父控制項,那麼後面的up事件就是到這裡touch觸發,不會在傳給它的子控制項。如果父控制項依然是false,那touch的處理就給到父控制項的父控制項,那麼up的事件處理都在父控制項的父控制項,不會觸發下面的。
返回true,如果是子控制項返回true,那麼它的touch事件都在這裡處理,父控制項是處理不了,因為它收不到子控制項傳給他的touch,被子控制項給攔截了。(這裡囉嗦了這麼多就是為了加深記憶,這個兩個事件理解起來都這麼麻煩了,更何況去記,記我肯定是一下子就忘的了^0^)
(註:可能你會覺得是否消費了有關係嗎,反正我已經針對事件編寫了處理代碼?答案是有區別!比如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就沒有。
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。
項目源碼
http://files.cnblogs.com/not-code/testtouchstudy.zip