Android中父View和子view的點選事件的執行過程

idaretobe發表於2015-01-14

Android中的事件型別分為按鍵事件和螢幕觸控事件,Touch事件是螢幕觸控事件的基礎事件,有必要對它進行深入的瞭解。 
一個最簡單的螢幕觸控動作觸發了一系列Touch事件:ACTION_DOWN->ACTION_MOVE->ACTION_MOVE->ACTION_MOVE...->ACTION_MOVE->ACTION_UP

當螢幕中包含一個ViewGroup,而這個ViewGroup又包含一個子view,這個時候android系統如何處理Touch事件呢?到底是
ViewGroup來處理Touch事件,還是子view來處理Touch事件呢?我只能很肯定的對你說不一定。呵呵,為什麼呢?看看下面我的調查結果你
就明白了。

android系統中的每個View的子類都具有下面三個和TouchEvent處理密切相關的方法:

1)public booleandispatchTouchEvent(MotionEvent ev)  這個方法用來分發TouchEvent

2)public boolean onInterceptTouchEvent(MotionEvent ev)這個方法用來攔截TouchEvent
3)public boolean onTouchEvent(MotionEvent ev)這個方法用來處理TouchEvent

當TouchEvent發生時,首先Activity將TouchEvent傳遞給最頂層的View, 
TouchEvent最先到達最頂層 view的 dispatchTouchEvent,然後由  dispatchTouchEvent方法進行分發,

如果dispatchTouchEvent返回true,則交給這個view的onTouchEvent處理,

如果 dispatchTouchEvent返回 false,則交給這個 view的 interceptTouchEvent方法來決定是否要攔截這個事件,
如果 interceptTouchEvent返回 true,也就是攔截掉了,則交給它的onTouchEvent來處理,
如果 interceptTouchEvent返回 false,那麼就傳遞給子 view,由子 view 的dispatchTouchEvent再來開始這個事件的分發。

如果事件傳遞到某一層的子 view的 onTouchEvent上了,這個方法返回了 false,那麼這個事件會從這個 view往上傳遞,都是onTouchEvent來接收。
如果事件傳遞到某一層的子view的onTouchEvent上了,這個方法返回true,那麼這個事件將不會向上傳遞了,由這個view攔截處理.
而如果傳遞到最上面的 onTouchEvent也返回 false的話,這個事件就會“消失”,而且接收不到下一次事件

onInterceptTouchEvent()用於處理事件並改變事件的傳遞方向。處理事件這個不用說了,你在函式內部編寫程式碼處理就可以了。而決定傳遞方向的是返回值,返回為false時事件會傳遞給子控制元件的onInterceptTouchEvent();返回值為true時事件會傳遞給當前控制元件的onTouchEvent(),而不在傳遞給子控制元件,這就是所謂的Intercept(截斷)。

onTouchEvent() 用於處理事件,返回值決定當前控制元件是否消費(consume)了這個事件。可能你要問是否消費了又區別嗎,反正我已經針對事件編寫了處理程式碼?答案是有區別!比如ACTION_MOVE或者ACTION_UP發生的前提是一定曾經發生了ACTION_DOWN,如果你沒有消費ACTION_DOWN,那麼系統會認為ACTION_DOWN沒有發生過,所以ACTION_MOVE或者ACTION_UP就不能被捕獲。

本文源地址:http://www.cnblogs.com/rocky_yi/archive/2011/01/21/1941522.html# ,轉載請註明出處!

複製程式碼
<?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>
複製程式碼

 

 

在沒有重寫onInterceptTouchEvent()和onTouchEvent()的情況下(他們的返回值都是false), 對上面這個佈局,MotionEvent事件的傳遞順序如下:

 

當某個控制元件的onInterceptTouchEvent()返回值為true時,就會發生截斷,事件被傳到當前控制元件的onTouchEvent()。如我們將LayoutView2的onInterceptTouchEvent()返回值為true,則傳遞流程變成:

 

 如果我們同時將LayoutView2的onInterceptTouchEvent()和onTouchEvent()設定成true,那麼LayoutView2將消費被傳遞的事件,同時後續事件(如跟著ACTION_DOWN的ACTION_MOVE或者ACTION_UP)會直接傳給LayoutView2的onTouchEvent(),不傳給其他任何控制元件的任何函式。同時傳遞給子空間一個ACTION_CANCEL事件。傳遞流程變成(圖中沒有畫出ACTION_CANCEL事件):

          

附SDK給出的說明:

·  You will receive the down event here.
·  The down event will be handled either by a child of this view group, or given to your own onTouchEvent() method to handle; this means you should implement onTouchEvent() to return true, so you will continue to see the rest of the gesture (instead of looking for a parent view to handle it). Also, by returning true from onTouchEvent(), you will not receive any following events in onInterceptTouchEvent() and all touch processing must happen in onTouchEvent() like normal.
·  For as long as you return false from this function, each following event (up to and including the final up) will be delivered first here and then to the target's onTouchEvent().
·  If you return true from here, you will not receive any following events: the target view will receive the same event but with the action ACTION_CANCEL, and all further events will be delivered to your onTouchEvent() method and no longer appear here.

相關文章