Android 中與 Touch 事件分發解析

隨筆- 90  文章- 0  評論- 42 


Android 中與 Touch 事件相關的方法包括:dispatchTouchEvent(MotionEvent ev)、onInterceptTouchEvent(MotionEvent ev)、onTouchEvent(MotionEvent ev);能夠響應這些方法的控件包括:ViewGroup、View、Activity。方法與控件的對應關係如下表所示:

Touch 事件相關方法

  方法功能 

  ViewGroup   

       View       

     Activity     

  public boolean dispatchTouchEvent(MotionEvent ev)

事件分發 

 Yes

 Yes

 Yes

  public boolean onInterceptTouchEvent(MotionEvent ev) 

事件攔截 

 Yes

 Yes

 No

  public boolean onTouchEvent(MotionEvent ev)

事件響應 

 Yes

 Yes

 Yes

從這張表中我們可以看到 ViewGroup 和 View 對與 Touch 事件相關的三個方法均能響應,而 Activity 對 onInterceptTouchEvent(MotionEvent ev) 也就是事件攔截不進行響應。另外需要注意的是 View 對 dispatchTouchEvent(MotionEvent ev) 和 onInterceptTouchEvent(MotionEvent ev) 的響應的前提是可以向該 View 中添加子 View,如果當前的 View 已經是一個最小的單元 View(比如 TextView),那麼就無法向這個最小 View 中添加子 View,也就無法向子 View 進行事件的分發和攔截,所以它沒有 dispatchTouchEvent(MotionEvent ev) 和 onInterceptTouchEvent(MotionEvent ev),只有 onTouchEvent(MotionEvent ev)。

一、Touch 事件分析

▐ 事件分發:public boolean dispatchTouchEvent(MotionEvent ev)

Touch 事件發生時 Activity 的 dispatchTouchEvent(MotionEvent ev) 方法會以隧道方式(從根元素依次往下傳遞直到最內層子元素或在中間某一元素中由於某一條件停止傳遞)將事件傳遞給最外層 View 的 dispatchTouchEvent(MotionEvent ev) 方法,並由該 View 的 dispatchTouchEvent(MotionEvent ev) 方法對事件進行分發。dispatchTouchEvent 的事件分發邏輯如下:

  • 如果 return true事件會分發給當前 View 並由 dispatchTouchEvent 方法進行消費,同時事件會停止向下傳遞;(case 5)
  • 如果 return false,事件分發分爲兩種情況:(case 1)
  1. 如果當前 View 獲取的事件直接來自 Activity,則會將事件返回給 Activity 的 onTouchEvent 進行消費;
  2. 如果當前 View 獲取的事件來自外層父控件,則會將事件返回給父 View 的  onTouchEvent 進行消費。
  • 如果返回系統默認的 super.dispatchTouchEvent(ev),事件會自動的分發給當前 View 的 onInterceptTouchEvent 方法。

    (ps:也就是說默認情況下,view 在dispatch時間的時候,會參考intercept)

▐ 事件攔截:public boolean onInterceptTouchEvent(MotionEvent ev) 

在外層 View 的 dispatchTouchEvent(MotionEvent ev) 方法返回系統默認的 super.dispatchTouchEvent(ev) 情況下,事件會自動的分發給當前 View 的 onInterceptTouchEvent 方法。onInterceptTouchEvent 的事件攔截邏輯如下:

  • 如果 onInterceptTouchEvent 返回 true,則表示將事件進行攔截,並將攔截到的事件交由當前 View 的 onTouchEvent 進行處理;
  • 如果 onInterceptTouchEvent 返回 false,則表示將事件放行,當前 View 上的事件會被傳遞到子 View 上,再由子 View 的 dispatchTouchEvent 來開始這個事件的分發;
  • 如果 onInterceptTouchEvent 返回 super.onInterceptTouchEvent(ev),事件默認會被攔截,並將攔截到的事件交由當前 View 的 onTouchEvent 進行處理。

  (ps:也就是說默認情況下,view 在intercept中會把事件截取下來自己處理)

▐ 事件響應:public boolean onTouchEvent(MotionEvent ev)

在 dispatchTouchEvent 返回 super.dispatchTouchEvent(ev) 並且 onInterceptTouchEvent 返回 true 或返回 super.onInterceptTouchEvent(ev) 的情況下 onTouchEvent 會被調用。onTouchEvent 的事件響應邏輯如下:

  • 如果事件傳遞到當前 View 的 onTouchEvent 方法,而該方法返回了 false,那麼這個事件會從當前 View 向上傳遞,並且都是由上層 View 的 onTouchEvent 來接收,如果傳遞到上面的 onTouchEvent 也返回 false,這個事件就會“消失”,而且接收不到下一次事件。
  • 如果返回了 true 則會接收並消費該事件。
  • 如果返回 super.onTouchEvent(ev) 默認處理事件的邏輯和返回 false 時相同。

    (ps:也就是說默認情況下,view 在onTouch後都把事件返回給parent)

到這裏,與 Touch 事件相關的三個方法就分析完畢了。下面的內容會通過各種不同的的測試案例來驗證上文中三個方法對事件的處理邏輯。


我舉得Touch事件不全部滿足優先原則


dispatch 不滿足

if(ev.getAction() == MotionEvent.ACTION_DOWN)

return true;

return super.dispathTouchEvent();

只有ACTION_DOWN沒有被傳遞

OnInterceptTouchEvent 不滿足

if(ev.getAction() == MotionEvent.ACTION_DOWN)

return false;

return true;

只有Action_Down傳到了ChildView,看case8,

OnTouchEvent 滿足


看case6,7




二、Touch 案例介紹

同樣在開始進行案例分析之前,我需要說明測試案例的結構,因爲所有的測試都是針對這一個案例來進行的,測試中只是通過修改每個控件中與 Touch 事件相關的三個方法的返回值來體現不同的情況。先來看張圖:


上面的圖爲測試案例的佈局文件 UI 顯示效果,佈局文件代碼如下:


<?xml version="1.0" encoding="utf-8"?>

<cn.sunzn.tevent.TouchEventFather xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    android:background="#468AD7"

    android:gravity="center"

    android:orientation="vertical" >


    <cn.sunzn.tevent.TouchEventChilds

        android:id="@+id/childs"

        android:layout_width="200dp"

        android:layout_height="200dp"

        android:layout_gravity="center"

        android:background="#E1110D"

        android:text="@string/hello" />


</cn.sunzn.tevent.TouchEventFather>


藍色背景爲一個自定義控件 TouchEventFather,該控件爲外層 View,繼承自 LinearLayout,實現代碼如下:


package cn.sunzn.tevent;


import android.content.Context;

import android.util.AttributeSet;

import android.util.Log;

import android.view.MotionEvent;

import android.widget.LinearLayout;


public class TouchEventFather extends LinearLayout {


    public TouchEventFather(Context context) {

        super(context);

    }


    public TouchEventFather(Context context, AttributeSet attrs) {

        super(context, attrs);

    }


    public boolean dispatchTouchEvent(MotionEvent ev) {

        Log.e("sunzn", "TouchEventFather | dispatchTouchEvent --> " + TouchEventUtil.getTouchAction(ev.getAction()));

        return super.dispatchTouchEvent(ev);

    }


    public boolean onInterceptTouchEvent(MotionEvent ev) {

        Log.i("sunzn", "TouchEventFather | onInterceptTouchEvent --> " + TouchEventUtil.getTouchAction(ev.getAction()));

        return super.onInterceptTouchEvent(ev);

    }


    public boolean onTouchEvent(MotionEvent ev) {

        Log.d("sunzn", "TouchEventFather | onTouchEvent --> " + TouchEventUtil.getTouchAction(ev.getAction()));

        return super.onTouchEvent(ev);

    }


}


紅色背景爲一個自定義控件 TouchEventChilds,該控件爲內層 View,爲 TouchEventFather 的子 View,同樣繼承自 LinearLayout,實現代碼如下:


package cn.sunzn.tevent;


import android.content.Context;

import android.util.AttributeSet;

import android.util.Log;

import android.view.MotionEvent;

import android.widget.LinearLayout;


public class TouchEventChilds extends LinearLayout {


    public TouchEventChilds(Context context) {

        super(context);

    }


    public TouchEventChilds(Context context, AttributeSet attrs) {

        super(context, attrs);

    }


    public boolean dispatchTouchEvent(MotionEvent ev) {

        Log.e("sunzn", "TouchEventChilds | dispatchTouchEvent --> " + TouchEventUtil.getTouchAction(ev.getAction()));

        return super.dispatchTouchEvent(ev);

    }


    public boolean onInterceptTouchEvent(MotionEvent ev) {

        Log.i("sunzn", "TouchEventChilds | onInterceptTouchEvent --> " + TouchEventUtil.getTouchAction(ev.getAction()));

        return super.onInterceptTouchEvent(ev);

    }


    public boolean onTouchEvent(MotionEvent ev) {

        Log.d("sunzn", "TouchEventChilds | onTouchEvent --> " + TouchEventUtil.getTouchAction(ev.getAction()));

        return super.onTouchEvent(ev);

    }


}


接着實現 Activity 的代碼,因爲控件所有的事件都是通過 Activity 的 dispatchTouchEvent 進行分發的;除此之外還需要重寫 Activity 的 onTouchEvent 方法,這是因爲如果一個控件直接從 Activity 獲取到事件,這個事件會首先被傳遞到控件的 dispatchTouchEvent 方法,如果這個方法 return false,事件會以冒泡方式返回給 Activity 的 onTouchEvent 進行消費。實現代碼如下:


package cn.sunzn.tevent;


import android.app.Activity;

import android.os.Bundle;

import android.util.Log;

import android.view.MotionEvent;


public class TouchEventActivity extends Activity {


    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

    }


    public boolean dispatchTouchEvent(MotionEvent ev) {

        Log.w("sunzn", "TouchEventActivity | dispatchTouchEvent --> " + TouchEventUtil.getTouchAction(ev.getAction()));

        return super.dispatchTouchEvent(ev);

    }


    public boolean onTouchEvent(MotionEvent event) {

        Log.w("sunzn", "TouchEventActivity | onTouchEvent --> " + TouchEventUtil.getTouchAction(event.getAction()));

        return super.onTouchEvent(event);

    }


}


最後再附上 TouchEventUtil 的代碼,TouchEventUtil 中並沒有做多少事情,只是將以上 2 個自定義控件中各個方法的 MotionEvent 集中到一個工具類中並將其對應的動作以 String 形式返回,這樣處理更便於實時觀察控件的事件。代碼如下:


package cn.sunzn.tevent;


import android.view.MotionEvent;


public class TouchEventUtil {

    

    public static String getTouchAction(int actionId) {

        String actionName = "Unknow:id=" + actionId;

        switch (actionId) {

        case MotionEvent.ACTION_DOWN:

            actionName = "ACTION_DOWN";

            break;

        case MotionEvent.ACTION_MOVE:

            actionName = "ACTION_MOVE";

            break;

        case MotionEvent.ACTION_UP:

            actionName = "ACTION_UP";

            break;

        case MotionEvent.ACTION_CANCEL:

            actionName = "ACTION_CANCEL";

            break;

        case MotionEvent.ACTION_OUTSIDE:

            actionName = "ACTION_OUTSIDE";

            break;

        }

        return actionName;

    }

    

}


三、Touch 案例分析

 Case 1 

攔截條件

控件名稱

dispatchTouchEvent 返回值

onInterceptTouchEvent 返回值

onTouchEvent 返回值

TouchEventActivity

super.dispatchTouchEvent(ev)

---

super.onTouchEvent(ev)

TouchEventFather

false

super.onInterceptTouchEvent(ev)

super.onTouchEvent(ev)

TouchEventChilds

super.dispatchTouchEvent(ev)

super.onInterceptTouchEvent(ev)

super.onTouchEvent(ev)

運行結果

Level

Time

PID

Application

Tag

 Text

 W

 05-10 03:41:19.743

 414

cn.sunzn.tevent

sunzn

  TouchEventActivity | dispatchTouchEvent --> ACTION_DOWN

 E

 05-10 03:41:19.743

 414

 cn.sunzn.tevent

sunzn

  TouchEventFather | dispatchTouchEvent --> ACTION_DOWN

 W

 05-10 03:41:19.743

 414

cn.sunzn.tevent

sunzn

  TouchEventActivity | onTouchEvent --> ACTION_DOWN

 W

 05-10 03:41:19.743

 414

 cn.sunzn.tevent

sunzn

  TouchEventActivity | dispatchTouchEvent --> ACTION_MOVE

 W

 05-10 03:41:19.743

 414

 cn.sunzn.tevent

sunzn

  TouchEventActivity | onTouchEvent --> ACTION_MOVE

 W

 05-10 03:41:19.743

 414

 cn.sunzn.tevent

sunzn

  TouchEventActivity | dispatchTouchEvent --> ACTION_MOVE

 W

 05-10 03:41:19.743

 414

 cn.sunzn.tevent

sunzn

  TouchEventActivity | onTouchEvent --> ACTION_MOVE

 W

 05-10 03:41:19.743

 414

 cn.sunzn.tevent

sunzn

  TouchEventActivity | dispatchTouchEvent --> ACTION_UP

 W

 05-10 03:41:19.743

 414

 cn.sunzn.tevent

sunzn

  TouchEventActivity | onTouchEvent --> ACTION_UP

結果分析

代碼運行後,事件首先由 TouchEventActivity 的 dispatchTouchEvent 方法分發給 TouchEventFather 控件的dispatchTouchEvent,而該控件的 dispatchTouchEvent 返回 false,表示對獲取到的事件停止向下傳遞,同時也不對該事件進行消費。由於 TouchEventFather 獲取的事件直接來自 TouchEventActivity ,則會將事件返回給 TouchEventActivity  的 onTouchEvent 進行消費,最後直接由 TouchEventActivity 來響應手指移動和擡起事件。

ps: 一旦dispatchTouchEvent return false以後,the following guesture 都會被停止傳遞。

  Case 2

攔截條件

控件名稱

dispatchTouchEvent 返回值

onInterceptTouchEvent 返回值

onTouchEvent 返回值

TouchEventActivity

super.dispatchTouchEvent(ev)

---

super.onTouchEvent(ev)

TouchEventFather

true

super.onInterceptTouchEvent(ev)

super.onTouchEvent(ev)

TouchEventChilds

super.dispatchTouchEvent(ev)

super.onInterceptTouchEvent(ev)

super.onTouchEvent(ev)

運行結果

Level

Time

PID

Application

Tag

 Text

 W

 05-10 03:41:19.743

 414

cn.sunzn.tevent 

sunzn

  TouchEventActivity | dispatchTouchEvent --> ACTION_DOWN

 E

 05-10 03:41:19.743

 414

 cn.sunzn.tevent

sunzn

  TouchEventFather | dispatchTouchEvent --> ACTION_DOWN

 W

 05-10 03:41:19.743

 414

cn.sunzn.tevent

sunzn

  TouchEventActivity | dispatchTouchEvent --> ACTION_MOVE

 E

 05-10 03:41:19.743

 414

 cn.sunzn.tevent

sunzn

  TouchEventFather | dispatchTouchEvent --> ACTION_MOVE

 W

 05-10 03:41:19.743

 414

 cn.sunzn.tevent

sunzn

  TouchEventActivity | dispatchTouchEvent --> ACTION_MOVE

 E

 05-10 03:41:19.743

 414

 cn.sunzn.tevent

sunzn

  TouchEventFather | dispatchTouchEvent --> ACTION_MOVE

 W

 05-10 03:41:19.743

 414

 cn.sunzn.tevent

sunzn

  TouchEventActivity | dispatchTouchEvent --> ACTION_MOVE

 E

 05-10 03:41:19.743

 414

 cn.sunzn.tevent

sunzn

  TouchEventFather | dispatchTouchEvent --> ACTION_MOVE

 W

 05-10 03:41:19.743

 414

 cn.sunzn.tevent

sunzn

  TouchEventActivity | dispatchTouchEvent --> ACTION_UP

E

 05-10 03:41:19.743

 414

 cn.sunzn.tevent

sunzn

  TouchEventFather | dispatchTouchEvent --> ACTION_UP

結果分析

代碼運行後,事件首先由 TouchEventActivity 的 dispatchTouchEvent 方法分發給 TouchEventFather 控件的 dispatchTouchEvent,而該控件的 dispatchTouchEvent 返回 true,表示分發事件到 TouchEventFather 控件並由該控件的 dispatchTouchEvent 進行消費;TouchEventActivity 不斷的分發事件到 TouchEventFather 控件的dispatchTouchEvent,而 TouchEventFather 控件的 dispatchTouchEvent 也不斷的將獲取到的事件進行消費。

 Case 3

攔截條件

控件名稱

dispatchTouchEvent 返回值

onInterceptTouchEvent 返回值

onTouchEvent 返回值

TouchEventActivity

super.dispatchTouchEvent(ev)

---

super.onTouchEvent(ev)

TouchEventFather

super.dispatchTouchEvent(ev)

true

super.onTouchEvent(ev)

TouchEventChilds

super.dispatchTouchEvent(ev)

super.onInterceptTouchEvent(ev)

super.onTouchEvent(ev)

運行結果

Level

Time

PID

Application

Tag

 Text

W

05-10 05:34:46.333

481

cn.sunzn.tevent

sunzn

  TouchEventActivity | dispatchTouchEvent --> ACTION_DOWN

E

05-10 05:34:46.333

481

cn.sunzn.tevent

sunzn

  TouchEventFather | dispatchTouchEvent --> ACTION_DOWN

I

05-10 05:34:46.333

481

cn.sunzn.tevent

sunzn

  TouchEventFather | onInterceptTouchEvent --> ACTION_DOWN

D

05-10 05:34:46.333

481

cn.sunzn.tevent

sunzn

  TouchEventFather | onTouchEvent --> ACTION_DOWN

W

05-10 05:34:46.333

481

cn.sunzn.tevent

sunzn

  TouchEventActivity | onTouchEvent --> ACTION_DOWN

W

05-10 05:34:46.343

481

cn.sunzn.tevent

sunzn

  TouchEventActivity | dispatchTouchEvent --> ACTION_MOVE

W

05-10 05:34:46.343

481

cn.sunzn.tevent

sunzn

  TouchEventActivity | onTouchEvent --> ACTION_MOVE

W

05-10 05:34:46.423

481

cn.sunzn.tevent

sunzn

  TouchEventActivity | dispatchTouchEvent --> ACTION_MOVE

W

05-10 05:34:46.423

481

cn.sunzn.tevent

sunzn

  TouchEventActivity | onTouchEvent --> ACTION_MOVE

W

05-10 05:34:46.433

481

cn.sunzn.tevent

sunzn

  TouchEventActivity | dispatchTouchEvent --> ACTION_MOVE

W

05-10 05:34:46.433

481

cn.sunzn.tevent

sunzn

  TouchEventActivity | onTouchEvent --> ACTION_MOVE

W

05-10 05:34:46.442

481

cn.sunzn.tevent

sunzn

  TouchEventActivity | dispatchTouchEvent --> ACTION_UP

W

05-10 05:34:46.442

481

cn.sunzn.tevent

sunzn

  TouchEventActivity | onTouchEvent --> ACTION_UP

結果分析

代碼運行後,事件首先由 TouchEventActivity 的 dispatchTouchEvent 方法分發給 TouchEventFather 控件的 dispatchTouchEvent,而該控件的 dispatchTouchEvent 返回 super.dispatchTouchEvent(ev),表示對事件進行分發並向下傳遞給 TouchEventFather 控件的 onInterceptTouchEvent 方法,該方法返回 true 表示對所獲取到的事件進行攔截並將事件傳遞給 TouchEventFather 控件的 onTouchEvent 進行處理,TouchEventFather 控件的 onTouchEvent 返回 super.onTouchEvent(ev) 表示對事件沒有做任何處理直接將事件返回給上級控件,由於 TouchEventFather 獲取的事件直接來自 TouchEventActivity,所以 TouchEventFather 控件的 onTouchEvent 會將事件以冒泡方式直接返回給 TouchEventActivity 的 onTouchEvent 進行消費,後續的事件則會跳過 TouchEventFather 直接由 TouchEventActivity 的 onTouchEvent 消費來自 TouchEventActivity 自身分發的事件。

 

case 6


攔截條件

控件名稱

dispatchTouchEvent 返回值

onInterceptTouchEvent 返回值

onTouchEvent 返回值

TouchEventActivity

super.dispatchTouchEvent(ev)

---

super.onTouchEvent(ev)

TouchEventFather

super.dispatchTouchEvent(ev)

true

if(ev.getAction() == MotionEvent.ACTION_MOVE)

return super.onTouchEvent(ev);

return true;

TouchEventChilds

super.dispatchTouchEvent(ev)

super.onInterceptTouchEvent(ev)

super.onTouchEvent(ev)

運行結果





攔截條件

控件名稱

dispatchTouchEvent 返回值

onInterceptTouchEvent 返回值

onTouchEvent 返回值

TouchEventActivity

super.dispatchTouchEvent(ev)

---

super.onTouchEvent(ev)

TouchEventFather

super.dispatchTouchEvent(ev)

true

if(ev.getAction() == MotionEvent.ACTION_DOWN)

return super.onTouchEvent(ev);

return true;

TouchEventChilds

super.dispatchTouchEvent(ev)

super.onInterceptTouchEvent(ev)

super.onTouchEvent(ev)

運行結果


結果分析

case 6和7只有Father的OnTouch不同,可以看出OnTouch中是一種優先原則

在官方OnInterceptTouchEvent中說


在case6中,因爲MotionEvent.ACTION_DOWN先滿足 return true條件的,所以接下來的guesture,即使是調用了super.OnTouchEvent,FatherView的OnTouchEvent依然能捕捉到每一個event

但是在case7中,MotionEvent.ACTION_DOWN先滿足 return super.OnTouchEvent(),所以接下來的所有guesture,FatherView全部都捕捉不到了


Case 4

攔截條件

控件名稱

dispatchTouchEvent 返回值

onInterceptTouchEvent 返回值

onTouchEvent 返回值

TouchEventActivity

super.dispatchTouchEvent(ev)

---

super.onTouchEvent(ev)

TouchEventFather

super.dispatchTouchEvent(ev)

false

super.onTouchEvent(ev)

TouchEventChilds

super.dispatchTouchEvent(ev)

super.onInterceptTouchEvent(ev)

super.onTouchEvent(ev)

運行結果

Level

Time

PID

Application

Tag

 Text

W

05-10 06:31:47.565

512

cn.sunzn.tevent

sunzn

  TouchEventActivity | dispatchTouchEvent --> ACTION_DOWN

E

05-10 06:31:47.565

512

cn.sunzn.tevent

sunzn

  TouchEventFather | dispatchTouchEvent --> ACTION_DOWN

I

05-10 06:31:47.565

512

cn.sunzn.tevent

sunzn

  TouchEventFather | onInterceptTouchEvent --> ACTION_DOWN

E

05-10 06:31:47.565

512

cn.sunzn.tevent

sunzn

  TouchEventChilds | dispatchTouchEvent --> ACTION_DOWN

I

05-10 06:31:47.565

512

cn.sunzn.tevent

sunzn

  TouchEventChilds | onInterceptTouchEvent --> ACTION_DOWN

D

05-10 06:31:47.565

512

cn.sunzn.tevent

sunzn

  TouchEventChilds | onTouchEvent --> ACTION_DOWN

D

05-10 06:31:47.565

512

cn.sunzn.tevent

sunzn

  TouchEventFather | onTouchEvent --> ACTION_DOWN

W

05-10 06:31:47.565

512

cn.sunzn.tevent

sunzn

  TouchEventActivity | onTouchEvent --> ACTION_DOWN

W

05-10 06:31:47.652

512

cn.sunzn.tevent

sunzn

  TouchEventActivity | dispatchTouchEvent --> ACTION_MOVE

W

05-10 06:31:47.652

512

cn.sunzn.tevent

sunzn

  TouchEventActivity | onTouchEvent --> ACTION_MOVE

W

05-10 06:31:47.732

512

cn.sunzn.tevent

sunzn

  TouchEventActivity | dispatchTouchEvent --> ACTION_MOVE

W

05-10 06:31:47.732

512

cn.sunzn.tevent

sunzn

  TouchEventActivity | onTouchEvent --> ACTION_MOVE

W

05-10 06:31:47.812

512

cn.sunzn.tevent

sunzn

  TouchEventActivity | dispatchTouchEvent --> ACTION_MOVE

W

05-10 06:31:47.812

512

cn.sunzn.tevent

sunzn

  TouchEventActivity | onTouchEvent --> ACTION_MOVE

W

05-10 06:31:47.892

512

cn.sunzn.tevent

sunzn

  TouchEventActivity | dispatchTouchEvent --> ACTION_UP

W

05-10 06:31:47.892

512

cn.sunzn.tevent

sunzn

  TouchEventActivity | onTouchEvent --> ACTION_UP

結果分析

代碼運行後,事件首先由 TouchEventActivity 的 dispatchTouchEvent 方法分發給 TouchEventFather 控件的 dispatchTouchEvent,而該控件的 dispatchTouchEvent 返回 super.dispatchTouchEvent(ev),表示對事件進行分發並向下傳遞給 TouchEventFather 控件的 onInterceptTouchEvent 方法,該方法返回 false 表示事件會被放行並傳遞到子控件 TouchEventChilds 的 dispatchTouchEvent 方法,同樣 TouchEventChilds 的 dispatchTouchEvent 返回 super.dispatchTouchEvent(ev),表示對事件進行分發並向下傳遞給 TouchEventChilds 控件的 onInterceptTouchEvent 方法,TouchEventChilds 的 onInterceptTouchEvent 方法返回 super.onInterceptTouchEvent(ev) 默認會將事件傳遞給 TouchEventChilds 的 onTouchEvent 進行處理,TouchEventChilds 的 onTouchEvent 返回 super.onTouchEvent(ev) 表示對事件沒有做任何處理直接將事件返回給上級控件,由於 TouchEventChilds 獲取的事件直接來自 TouchEventFather,所以 TouchEventChilds 控件的 onTouchEvent 會將事件以冒泡方式直接返回給 TouchEventFather 的 onTouchEvent 進行消費,而 TouchEventFather 的 onTouchEvent 也返回了 super.onTouchEvent(ev),同樣 TouchEventFather 的 onTouchEvent 也會將事件返回給上級控件,而 TouchEventFather 獲取的事件直接來自 TouchEventActivity,所以 TouchEventFather 控件的 onTouchEvent 會將事件以冒泡方式直接返回給 TouchEventActivity 的 onTouchEvent 進行消費,後續的事件則會跳過 TouchEventFather 和 TouchEventChilds 直接由 TouchEventActivity 的 onTouchEvent 消費來自 TouchEventActivity 自身分發的事件。

 Case 5

攔截條件

控件名稱

dispatchTouchEvent 返回值

onInterceptTouchEvent 返回值

onTouchEvent 返回值

TouchEventActivity

super.dispatchTouchEvent(ev)

---

super.onTouchEvent(ev)

TouchEventFather

super.dispatchTouchEvent(ev)

false

super.onTouchEvent(ev)

TouchEventChilds

true

super.onInterceptTouchEvent(ev)

super.onTouchEvent(ev)

運行結果

Level

Time

PID

Application

Tag

 Text

 W

 05-10 08:11:18.403

574

 cn.sunzn.tevent

 sunzn

  TouchEventActivity | dispatchTouchEvent --> ACTION_DOWN

 E

 05-10 08:11:18.403

574

 cn.sunzn.tevent

 sunzn

  TouchEventFather | dispatchTouchEvent --> ACTION_DOWN

 I

 05-10 08:11:18.403

574

 cn.sunzn.tevent

 sunzn

  TouchEventFather | onInterceptTouchEvent --> ACTION_DOWN

 E

 05-10 08:11:18.403

574

 cn.sunzn.tevent

 sunzn

  TouchEventChilds | dispatchTouchEvent --> ACTION_DOWN

 W

 05-10 08:11:19.652

574

 cn.sunzn.tevent

 sunzn

  TouchEventActivity | dispatchTouchEvent --> ACTION_MOVE

 E

 05-10 08:11:19.652

574

 cn.sunzn.tevent

 sunzn

  TouchEventFather | dispatchTouchEvent --> ACTION_MOVE

 I

 05-10 08:11:19.652

574

 cn.sunzn.tevent

 sunzn

  TouchEventFather | onInterceptTouchEvent --> ACTION_MOVE

E

 05-10 08:11:19.652

574

cn.sunzn.tevent

sunzn

  TouchEventChilds | dispatchTouchEvent --> ACTION_MOVE

 W

 05-10 08:11:19.872

574

cn.sunzn.tevent

 sunzn

  TouchEventActivity | dispatchTouchEvent --> ACTION_UP

E

05-10 08:11:19.872

574

cn.sunzn.tevent

sunzn

  TouchEventFather | dispatchTouchEvent --> ACTION_UP

I

05-10 08:11:19.872

574

cn.sunzn.tevent

sunzn

  TouchEventFather | onInterceptTouchEvent --> ACTION_UP

 E

 05-10 08:11:19.872

574

cn.sunzn.tevent

 sunzn

  TouchEventChilds | dispatchTouchEvent --> ACTION_UP

結果分析

代碼運行後,事件首先由 TouchEventActivity 的 dispatchTouchEvent 方法分發給 TouchEventFather 控件的 dispatchTouchEvent,該控件的 dispatchTouchEvent 返回super.dispatchTouchEvent(ev),事件會分發到 TouchEventFather 的 onInterceptTouchEvent,onInterceptTouchEvent 返回 false 表示放行當先事件;事件會被傳遞到子控件 TouchEventChilds 的 dispatchTouchEvent 方法,dispatchTouchEvent 返回 true 表示事件被分發到 TouchEventChilds 控件並由該控件的 dispatchTouchEvent 方法消費。後續的事件也會不斷的重複上面的邏輯最終被 TouchEventChilds 的 dispatchTouchEvent 消費。


case8

攔截條件

控件名稱

dispatchTouchEvent 返回值

onInterceptTouchEvent 返回值

onTouchEvent 返回值

TouchEventActivity

super.dispatchTouchEvent(ev)

---

super.onTouchEvent(ev)

TouchEventFather

super.dispatchTouchEvent(ev)

if(ev.getAction() == MotionEvent.ACTION_DOWN)

return false;

return true;

true

TouchEventChilds

super.dispatchTouchEvent(ev)

super.onInterceptTouchEvent(ev)

true



case 9:一旦收到了ACTION_CANCLE,following guesture就再也收不到了,而且,這個cancel event在Ontouchevent中也會按正常event處理,即如果子View 返回true,FatherView就收不到;反之,則收的到,而且收到的不是ACTION_CANCEL,原來是什麼就收到什麼

攔截條件

控件名稱

dispatchTouchEvent 返回值

onInterceptTouchEvent 返回值

onTouchEvent 返回值

TouchEventActivity

super.dispatchTouchEvent(ev)

---

super.onTouchEvent(ev)

TouchEventFather

super.dispatchTouchEvent(ev)

if(ev.getAction() == MotionEvent.ACTION_DOWN

||ev.getAction() == MotionEvent.ACTION_UP)

return false;

return true;

false

TouchEventChilds

super.dispatchTouchEvent(ev)

super.onInterceptTouchEvent(ev)

true


可以看出,ChildView收不到最後一個ACTION_UP

這裏我最不明白的就是 明明在FatherView中,Ontouch我每次都返回false,按道理來說,Ontouch就只能捕獲一次事件,以後的直接交給Activity去處理的,

但是這裏Ontouch居然每次都捕獲了。。。。我估計跟FatherView裏onInterceptTouchEvent第一次返回了false有關

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章