android 之 事件傳遞

首先,這篇文章僅僅針對於由於觸摸(Touch)而觸發的事件。

Android的事件:onClick, onScroll, onFling等等,都是由許多個Touch組成的。其中Touch的第一個狀態肯定是ACTION_DOWN, 表示按下了屏幕。之後,touch將會有後續事件,可能是:

  • ACTION_MOVE //表示爲移動手勢

  • ACTION_UP //表示爲離開屏幕

  • ACTION_CANCEL //表示取消手勢,不會由用戶產生,而是由程序產生的

一個Action_DOWN, n個ACTION_MOVE, 1個ACTION_UP,就構成了Android中衆多的事件。

在Android中,有一類控件其中還可以包含其他的子控件,這類控件是繼承於ViewGroup類(枝幹View),例如:ListView, Gallery, GridView, LinearLayout等。

還有一類控件是不能再包含子控件,例如:TextView()。

本文的主要討論對象就是ViewGroup類的控件嵌套時事件觸發情況。

對於ViewGroup類的控件,有一個很重要的方法,就是onInterceptTouchEvent(),用於處理事件並改變事件的傳遞方向,它的返回值是一個布爾值,決定了Touch事件是否要向它包含的子View繼續傳遞,這個方法是從父View向子View傳遞。

而方法onTouchEvent(),用於接收事件並處理,它的返回值也是一個布爾值,決定了事件及後續事件是否繼續向上傳遞,這個方法是從子View向父View傳遞。

touch事件在 onInterceptTouchEvent()和onTouchEvent以及各個childView間的傳遞機制完全取決於onInterceptTouchEvent()和onTouchEvent()的返回值。返回值爲true表示事件被正確接收和處理了,返回值爲false表示事件沒有被處理,將繼續傳遞下去。

ACTION_DOWN事件會傳到某個ViewGroup類的onInterceptTouchEvent,如果返回false,則DOWN事件繼續向子ViewGroup類的onInterceptTouchEvent傳遞,如果子View不是ViewGroup類的控件,則傳遞給它的onTouchEvent。

如果onInterceptTouchEvent返回了true,則DOWN事件傳遞給它的onTouchEvent,不再繼續傳遞,並且之後的後續事件也都傳遞給它的onTouchEvent。

如果某View的onTouchEvent返回了false,則DOWN事件繼續向其父ViewGroup類的onTouchEvent傳遞;如果返回了true,則後續事件會直接傳遞給其onTouchEvent繼續處理。(後續事件只會傳遞給對於必要事件ACTION_DOWN返回了true的onTouchEvent)

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

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

通過以下代碼說明一下葉子View被點擊後事件的傳遞:

<com.example.testevent.LinearLayout1 xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin" >

    <com.example.testevent.LinearLayout2
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <com.example.testevent.TextView1
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/hello_world" />
        <com.example.testevent.TextView2
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/hello_world" />
    </com.example.testevent.LinearLayout2>

</com.example.testevent.LinearLayout1>

TextView1被點擊後如果onInterceptTouchEvent和onTouchEvent都用系統默認的返回值false,則傳遞方向是LinearLayout1_onInterceptTouchEvent

-->LinearLayout2_onInterceptTouchEvent-->TextView1_onTouchEvent-->LinearLayout2_onTouchEvent-->LinearLayout1_onTouchEvent; 點擊TextView2也是同理

原來以爲點擊葉子View之後他的onTouchEvent會馬上執行,現在看來是從頂級父控件一層層傳遞下來的;而枝幹View的onTouchEvent是否執行要依賴於他的onInterceptTouchEvent的返回值(爲true則執行)或當前枝幹View和葉子View之間(包括葉子View)的控件的onTouchEvent是否消耗了此事件(沒有消耗則會執行);

上面的枝幹View、葉子View是自己約定的命名(枝幹View是可以重寫onInterceptTouchEvent函數的,事件可以往下傳遞;而葉子View沒有onInterceptTouchEvent函數是不可以重寫的,事件只能往上傳遞)。

還有一些相關介紹:

http://www.360doc.com/content/12/0823/21/7662927_231975338.shtml

參考:http://www.cnblogs.com/rocky_yi/archive/2011/01/21/1941522.html#


發佈了21 篇原創文章 · 獲贊 6 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章