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

淺析android事件分發機制

編輯:關於Android編程

我覺得android中的事件分發機制的懵懂期應該是Listview中對於item的點擊和長按事件,那個時候知道item的長按事件是返回boolean值的方法,我們知道要把那個false改成true。。。這樣我們長按事件結束後就不會再繼續觸發點擊事件了

一、引言

1、關於listview中的item點擊事件以及item長按事件的引入(本來是想跟onClick事件一起的,然後就發現一個問題了):Don’t call setOnClickListener for an AdapterView. You probably want setOnItemClickListener instead,就是說android設計中不允許給類似listview的控件(AdapterView)直接寫onClick事件。

//listview中的item點擊事件
lvProduct.setOnItemClickListener(new AdapterView.OnItemClickListener() {
           @Override
           public void onItemClick(AdapterView adapterView, View view, int i, long l) {
               Log.e(Tag,"onItemClick");
           }
       });

//listview中的item長按事件
        lvProduct.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(AdapterView adapterView, View view, int i, long l) {
                Log.e(Tag,"onItemLongClick");
                return false;
            }
        });

我們通過log打印下,在onItemLongClick分別返回false以及true的情況下:

1).返回false的情況下長按item

這裡寫圖片描述

2).返回true的情況下長按item
這裡寫圖片描述

我們會發現我們執行長按操作的時候應該是先點擊了這個item然後不動持續一段時間。其實這跟我們的事件消費很相似,如果在長按事件下返回了true,那麼表示這個事件被消費了,然後就不會在繼續傳遞這個動作了。但是如果返回了false,表示這個事件動作還會繼續傳遞,因為你長按item的時候也是點擊了這個item,所以會執行onItemClick事件。

2、再比如,我們再一個Textview上寫onClick事件以及onTouch事件做個試驗:

//點擊事件
        textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                Log.w(Tag,"onClick");
            }
        });

        //觸摸事件
        textView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                Log.w(Tag,"onTouch");
                return false;
            }
        });

我們通過log打印下在onTouch事件中返回true和false的兩種情況:

1)返回false

正常點擊

 

這裡寫圖片描述

 

正常點擊加移動

 

這裡寫圖片描述

 

2)返回true

正常點擊:

 

這裡寫圖片描述

 

正常點擊加移動

 

這裡寫圖片描述

同理我們會發現textview中的現象與我們之前驗證的基本吻合,如果返回true表示事件被消費,將不再繼續傳遞這個動作,如果返回false表示這個動作將會繼續傳遞。但是為什麼onTouch事件會執行兩次或者多次呢,這是因為執行onTouch事件會進行3種基本的操作ACTION_DOWN(手指按下),ACTION_UP(手指抬起),ACTION_MOVE(手指移動)。所以點擊的時候就執行ACTION_DOWN以及ACTION_UP兩次的操作,但是如果你的手指移動了的話,還會進行多次ACTION_MOVE的操作。

二、正題:關於Touch事件分發機制的探索

1、Touch事件的主角們,無非就是與用戶直接交互的Activity,ViewGroup以及View,Touch事件的參與方法也就是事件分發(dispatchTouchEvent),事件攔截(onInterceptTouchEvent),事件響應(onTouchEvent)。這裡需要說明的是Activity中沒有事件攔截,View中也沒有事件攔截,可以理解成是事件攔截是ViewGroup對於自己的子View的Touch事件進行攔截,其實ViewGrop是繼承View的子類,用來充當View的容器,將其中的View視作自己的孩子,對它的子View進行管理,當然它的孩子也可以是ViewGroup類型。所以可以把ViewGroup看做是一個View的集合。

這裡寫圖片描述

2、Touch事件分發的實質:

當我們手指點擊某個控件的時候,其實是分發找出ACTION_DOWN這個動作的真正實施者,找到這個動作真正的實施者後,將這次事件交給這個實施者進行消費(返回True),那麼這次的動作算是完成了。

3、手指點擊Button的事件分發流程:
假設我們的手指點擊了一個Activity中的Button,假設這個Button在一個ViewGroup中,而這個那麼用戶可以直接看到的是Activity,場景如下(首先應該了解的是ViewGroup的樹形結構,一個ViewGroup包含若干個View):

這裡寫圖片描述

那麼我們的手指點擊了可見的某一個View,那麼Touch事件的ACTION_DOWN會進行事件分發(dispatchTouchEvent),調用的順序為:1-2-3-6-7-8–4-5,事件分發過程中遇到ViewGroup的時候,首先會判斷ViewGroup的onInterceptTouchEvent是否攔截,如果不攔截,那麼本次事件繼續分發;dispatchTouchEvent事件的返回值為boolean,如果遍歷分發的過程中返回了true,那麼本次分發結束,找到了消費對象,將執行那個View的onTouchEvent事件。加入我們點擊了6號的View,那麼dispatchTouchEvent執行到6號的時候就會中斷,7-8-4-5都不會執行到。那麼需要注意的是1、2、3、6事件都執行了ACTION_DOWN的操作,而只有6號View執行了本次Touch的完整事件。假設分發過程中所有的dispatchTouchEvent都返回了false,那麼本次的Touch事件就由Activity進行消費了。

三、總結:

1.ViewGrop是繼承View的子類,用來充當View的容器,將其中的View視作自己的孩子,對它的子View進行管理,當然它的孩子也可以是ViewGroup類型。所以可以把ViewGroup看做是一個View的集合。

2.ViewGrop和View組成了一個樹狀結果,根節點為Activity。事件分發dispatchTouchEvent分發按照樹形從左到右遞歸遍歷,事件分發是分發ACTION_DOWN的動作。

3.一個完整的Touch事件由一個Action_Down、若干個Action_Move(可以沒有)、一個Aciton_UP組成

4.當Acitivty接收到Touch事件時,將遍歷子View進行ACTION_Down事件的分發。ViewGroup的遍歷可以看成是遞歸的。分發的目的是為了找到真正要處理本次完整觸摸事件的View,找到這個View後會在dispathTouchEvent事件中返回true結束本次ACTION_Down的分發,這個View會在onTouchEvent處理本次事件消費並返回true。

5.onInterceptTouchEvent攔截事件是ViewGroup所特有的攔截自己的子View的ACTION_DOWN事件的分發,使自己獲取本次分發的消費的權利,中止本次事件分發。

6.當本次事件分發所有子View都不處理(返回false),那麼久會觸發Acitivity的onTouchEvent方法,有Activity做本次事件的消費。

7.默認不復寫事件分發機制的方法的話,所有的返回結果都為false。如果要做本次事件分發的終結點的話,記得要把onTouchEvent的返回結果改為true,結束本次Touch事件的傳遞。

好了,我大概只知道這麼多了~~我覺得完全可以轉載別人的博客,但是我覺得應該把自己理解的融合別人的博客,把自己的想法show出來,哪怕只是抄一遍,也比ctrl+c,ctrl+v來的好。重復造輪子是難逃的宿命了,哎哎~

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