Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 完全理解android事件分發機制

完全理解android事件分發機制

編輯:關於Android編程

前言

現在看來其實更像是一篇知識概括,多處可能未講清楚,於是打算重寫事件分發,用一篇文章大致講清楚。
首先,形式上筆者最先思考的是使用源碼,此者能從原理上講解分發機制,比起侃侃而談好得多。但是大量的源碼往往會讓新手產生畏懼難以理解,於是筆者最終還是打算主要使用實例log輸出來讓讀者理解android事件分發。

重要函數

筆者此次主要提及最常用的幾個函數:
(其間區別看源碼很容易理解,此處直接給上結果)
onClick():這個函數是是View提供給我們的OnClickListener這個接口中的函數,在這裡可以自定義對點擊事件的處理邏輯。會在onTouchEvent()中進行調用。
onTouch():這個函數是View提供給我們的OnTouchListener這個接口中的函數,在這裡面可以自定義對觸摸事件的處理邏輯。
onTouchEvent():這個函數是view內部的觸摸事件的處理方式,其間包括獲取焦點,調用onClick()等等。
dispatchTouchEvent():這個是View的事件分發函數,在ViewGroup中進行重寫。在View中其間會調用onTouchEvent(),在ViewGroup中其間會調用onInterceptTouchEvent()和onTouchEvent()。
onInterceptTouchEvent():這個函數是事件攔截函數,是ViewGroup才有的函數。

重要函數執行順序

此處我們通過一個很簡單的例子進行說明,示例:
這裡寫圖片描述
示例xml代碼如下:




    

        
    



由外到裡主要是三個LinearLayout,分別為A、B、C。筆者分別在五個關鍵函數中加上了Log,最終點擊一下,輸出的值如下:

01-12 01:28:58.136 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_A
01-12 01:28:58.136 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_A
01-12 01:28:58.136 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_B
01-12 01:28:58.136 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_B
01-12 01:28:58.136 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_C
01-12 01:28:58.136 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_C
01-12 01:28:58.136 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouch_C
01-12 01:28:58.136 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouchEvent_C
01-12 01:28:58.203 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_A
01-12 01:28:58.203 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_A
01-12 01:28:58.203 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_B
01-12 01:28:58.203 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_B
01-12 01:28:58.203 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_C
01-12 01:28:58.203 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouch_C
01-12 01:28:58.203 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouchEvent_C
01-12 01:28:58.203 2442-2442/com.example.double2.dispatchevent D/XJJ: onClick_C

如上,我們可以看到五個函數的大致執行順序如下:

dispatchTouchEvent() onInterceptTouchEvent() onTouch() onTouchEvent() onClick()

好奇的讀者肯定會問,為什麼事件分發執行了兩次呢?
其實很簡單,因為的確有兩個分發的事件,一次是“手指按下”的事件,一次是“手指抬起”的事件。我們可以看到,只有在“手指抬起”的時候,才會觸發onClick()事件。

此處為了便於大家理解,也附上一張事件分發的圖:
這裡寫圖片描述

控制事件分發

然而還有一個值得我們在意的事情,就是onTouch()以及onTouchEvent()只有在C中執行,而在B和A的就不執行了。
此處,我們就必須再講一點了。

dispatchTouchEvent()、onInterceptTouchEvent() 、onTouch()、onTouchEvent()這四個函數,返回值為false的時候,事件會繼續向下分發,一旦返回值為true,事件就不再向下分發。
而onClick()沒有返回值

根據這點我們可以知道,一定是C的onTouchEvent()中返回了true,我們將其更改後再看一下效果。
原來的代碼為:

@Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.d("XJJ","onTouchEvent_C");
        return super.onTouchEvent(event);
    }

更改後:

@Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.d("XJJ","onTouchEvent_C");
        return false;
    }

效果:

01-12 01:24:06.250 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_A
01-12 01:24:06.250 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_A
01-12 01:24:06.250 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_B
01-12 01:24:06.250 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_B
01-12 01:24:06.250 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_C
01-12 01:24:06.250 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_C
01-12 01:24:06.250 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouch_C
01-12 01:24:06.250 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouchEvent_C
01-12 01:24:06.250 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouch_B
01-12 01:24:06.250 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouchEvent_B
01-12 01:24:06.360 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_A
01-12 01:24:06.360 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_A
01-12 01:24:06.360 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_B
01-12 01:24:06.360 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouch_B
01-12 01:24:06.360 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouchEvent_B
01-12 01:24:06.360 2442-2442/com.example.double2.dispatchevent D/XJJ: onClick_B

這樣操作之後,我們可以發現,“手指按下”時,onTouch()以及onTouchEvent()事件就可以傳遞到B了。但是同時,我們也可以發現,當“手指抬起”時,C的onTouch()以及onTouchEvent()事件就不會執行了。

當然,如果需要onTouch()以及onTouchEvent()事件傳遞到A,那麼只需要將B的onTouchEvent()也返回false即可。(此處就不重復演示了)

那麼如果onTouchEvent()返回值設置為true了之後,是不是onClick()事件是不是就不會執行了呢?效果如下:

01-12 01:39:21.560 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_A
01-12 01:39:21.560 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_A
01-12 01:39:21.560 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_B
01-12 01:39:21.560 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_B
01-12 01:39:21.560 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_C
01-12 01:39:21.560 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_C
01-12 01:39:21.560 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouch_C
01-12 01:39:21.560 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouchEvent_C
01-12 01:39:21.617 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_A
01-12 01:39:21.617 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_A
01-12 01:39:21.617 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_B
01-12 01:39:21.617 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_B
01-12 01:39:21.617 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_C
01-12 01:39:21.617 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouch_C
01-12 01:39:21.617 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouchEvent_C

onClick()的確是不會執行了,如此我們也嘗試一下onTouch()返回值設置為true,效果如下:

01-12 01:40:41.101 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_A
01-12 01:40:41.101 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_A
01-12 01:40:41.101 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_B
01-12 01:40:41.101 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_B
01-12 01:40:41.101 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_C
01-12 01:40:41.101 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_C
01-12 01:40:41.101 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouch_C
01-12 01:40:41.173 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_A
01-12 01:40:41.173 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_A
01-12 01:40:41.173 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_B
01-12 01:40:41.173 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_B
01-12 01:40:41.173 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_C
01-12 01:40:41.173 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouch_C

如此,我們可知,當onTouch()返回值設置為true的時候,onTouchEvent()的確是不會執行了。

到這裡,我們其實只剩下對onInterceptTouchEvent() 的分析了,為何沒有dispatchTouchEvent()了呢?
因為dispatchTouchEvent()是事件分發的函數,對View而言,我們阻止它內部的事件分發是沒有什麼意義的,而我們要控制ViewGroup的事件分發則是通過onInterceptTouchEvent() 來執行的。

如此我們便假設一個應用場景,A包括B,B包括C,B為橫向滑動,C為豎向滑動,當橫向滑動的加速度大於豎向滑動的加速度的時候,我們僅僅讓B響應事件,而不把事件傳遞給C。

我們可以通過onInterceptTouchEvent() 來實現,僅僅只需將B的onInterceptTouchEvent()返回值設置為true即可,效果如下:

01-12 01:50:18.513 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_A
01-12 01:50:18.513 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_A
01-12 01:50:18.513 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_B
01-12 01:50:18.513 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_B
01-12 01:50:18.513 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouch_B
01-12 01:50:18.513 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouchEvent_B
01-12 01:50:18.621 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_A
01-12 01:50:18.621 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_A
01-12 01:50:18.621 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_B
01-12 01:50:18.621 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouch_B
01-12 01:50:18.621 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouchEvent_B
01-12 01:50:18.621 2442-2442/com.example.double2.dispatchevent D/XJJ: onClick_B

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved