那些你曾不知道的觸摸事件—Android分發機制徹底解析

最近在作高德地圖的時候,因爲用戶的要求,不得不用ScrollVew嵌套MapView,雖然很官方要求不建議這樣作,但也迫於無奈... 魔高一尺,道高一丈.有什麼事是程序員不能解決的,若是有那就是解決兩次.html

鑑於用到了觸摸事件,因而就來總結了Android的觸摸事件機制.android

首先當用戶進行屏幕操做的時候,則有兩種狀況程序員

  • 一是按鍵事件bash

  • 二是觸摸事件微信

按鍵事件分爲長按和點擊事件,過於簡單,這裏再也不進行總結.ide

觸摸事件

觸摸事件的組成:函數

  • 一個actionDown
  • n個actionMove
  • 一個actionUp
  • 一個onClick
  • 一個onLongClick
  • 一個onScroll

Android組件

  • 繼承 ViewGroupo好比LinearLayout,ScrollView,GridView,extends-->ViewGroup的View
  • ViewGroup容器
  • 繼承於 View不包含其餘的View ,如TextView,Edittext,Butto等

下面介紹一個講的好的一個博客地址:學習

www.trinea.cn/android/tou…ui

MotionEvent

全部Touch事件都被封裝成了MotionEvent對象,包括Touch的位置、時間、歷史記錄以及第幾個手指(多指觸摸)等。spa

Android 事件的處理的分類

  • 分發(不少人也稱做爲傳遞事件) : dispatchTouchEvent函數

  • 消費: onTouchEvent函數和OnTouchListener函數

  • 攔截:onInterceptTouchEvent函數

咱們都知道Android的觸摸事件都是從外層傳遞到內層:由最外層的Activity——>ViewGroup——> ViewGroupo——>.......View.

第一觸摸事件傳遞的開始必定是Activity;

第二傳遞方式是經過隧道方式傳遞;

第三一直傳遞到一個最外層的View,也就是頂級View,由該View的這個方法來進行分發。

對於Activity來講:

@Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        boolean isFlag = super.dispatchTouchEvent(ev);
        return isFlag;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        boolean isFlag = super.onTouchEvent(event);
        return isFlag;
    }複製代碼

對於ViewGroup來講:

@Override
    public boolean onTouchEvent(MotionEvent event) {
        boolean isFlag =super.onTouchEvent(event);
        return  isFlag;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        boolean isFlag =super.onInterceptTouchEvent(event);
        return  isFlag;
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        boolean isFlag =super.dispatchTouchEvent(event);
        return  isFlag;
    }複製代碼

對於View來講和Activity同樣,只有消費和攔截

@Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        boolean isFlag = super.dispatchTouchEvent(ev);
        return isFlag;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        boolean isFlag = super.onTouchEvent(event);
        return isFlag;
    }複製代碼

www.open-open.com/lib/view/op…

android中的Touch事件都是從ACTION_DOWN開始的:

單手指操做:ACTION_DOWN---ACTION_MOVE----ACTION_UP

多手指操做:ACTION_DOWN---ACTION_POINTER_DOWN---ACTION_MOVE--ACTION_POINTER_UP---ACTION_UP.

若是都不進行攔截,都不消費的基本流程圖:

Markdown
Markdown

下面咱們就用案例進行分析:

activity----》ViewGroup(MyLinearLayout)---》ViewGroup(MySubView)

MyLinearLayout的dispatchTouchEvent返回false。

Markdown
Markdown

打印結果:

Markdown
Markdown

  • 過程及結果分析:
  • 事件首先由 TouchEventActivity 的 dispatchTouchEvent 方法分發給 TouchEventFather 控件的dispatchTouchEvent;

  • 而該TouchEventFather 控件的 dispatchTouchEvent 返回 false,表示對獲取到的事件中止向下傳遞,同時也不對該事件進行消費;

  • 因爲 TouchEventFather 獲取的事件直接來自 TouchEventActivity ,則會將事件返回給 TouchEventActivity 的 onTouchEvent 進行消費;

  • 最後直接由 TouchEventActivity 來響應手指移動和擡起事件。

MyLinearLayout的dispatchTouchEvent返回true。

Markdown
Markdown

打印結果:

Markdown
Markdown

  • 過程及結果分析:
  • 事件首先由 TouchEventActivity 的 dispatchTouchEvent 方法分發給 TouchEventFather 控件的 dispatchTouchEvent;

  • 而該TouchEventFather 控件的 dispatchTouchEvent 返回 true,表示分發事件到 TouchEventFather 控件並由該控件的 dispatchTouchEvent 進行消費;

  • 又由於TouchEventActivity 不斷的分發事件到 TouchEventFather 控件的 dispatchTouchEvent,而 TouchEventFather 控件的 dispatchTouchEvent 也不斷的將獲取到的事件進行消費。

MyLinearLayout的onInterceptTouchEvent返回true。

Markdown
Markdown

打印結果:

Markdown
Markdown

  • 過程及結果分析:

  • 事件首先由 TouchEventActivity 的 dispatchTouchEvent 方法分發給 TouchEventFather 控件的 dispatchTouchEvent;

  • 而該TouchEventFather 控件的 dispatchTouchEvent 返回 super.dispatchTouchEvent(ev),表示對事件進行分發並向下傳遞給 TouchEventFather 控件的 onInterceptTouchEvent 方法;

  • 而該方法返回 true 表示對所獲取到的事件進行攔截並將事件傳遞給 TouchEventFather 控件的 onTouchEvent 進行處理,TouchEventFather 控件的 onTouchEvent 返回 super.onTouchEvent(ev) 表示對事件沒有作任何處理直接將事件返回給上級控件;

  • 因爲 TouchEventFather 獲取的事件直接來自 TouchEventActivity,因此 TouchEventFather 控件的 onTouchEvent 會將事件以冒泡方式直接返回給 TouchEventActivity 的 onTouchEvent 進行消費;

  • 後續的事件則會跳過 TouchEventFather 直接由 TouchEventActivity 的 onTouchEvent 消費來自 TouchEventActivity 自身分發的事件。

MyLinearLayout的onInterceptTouchEvent返回false。

Markdown
Markdown

打印結果:

Markdown
Markdown

  • 過程及結果分析:

  • 事件首先由 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 自身分發的事件。

MyLinearLayout的onInterceptTouchEvent返回false。MySubView返回true

Markdown
Markdown

打印結果:

Markdown
Markdown

  • 過程及結果分析:

  • 事件首先由 TouchEventActivity 的 dispatchTouchEvent 方法分發給 TouchEventFather 控件的 dispatchTouchEvent;

  • 該控件的 dispatchTouchEvent 返回 super.dispatchTouchEvent(ev),事件會分發到 TouchEventFather 的 onInterceptTouchEvent,此方法返回 false 表示放行當先事件;

  • 事件會被傳遞到子控件 TouchEventChilds 的 dispatchTouchEvent 方法,dispatchTouchEvent 返回 true 表示事件被分發到 TouchEventChilds ,並由 dispatchTouchEvent 方法消費;

  • 後續的事件也會不斷的重複上面的邏輯最終被 TouchEventChilds 的 dispatchTouchEvent 消費。

其實若是看源碼的話比較複雜,總結一下,基本的規則是:

  • down事件首先會傳遞到onInterceptTouchEvent()方法

  • 若是該ViewGroup的onInterceptTouchEvent()在接收到down事件處理完成以後return false,內部view將也會獲取到down,那麼後續的move, up等事件將繼續會先傳遞給該ViewGroup,以後同樣傳遞給最終的目標view的onTouchEvent()處理。

  • 若是該ViewGroup的onInterceptTouchEvent()在接收到down事件處理完成以後return true,內部view不會貨到down,後續的move, up等事件也再也不傳遞給onInterceptTouchEvent(),固然,move,up也不會傳給view

  • 若是最終須要處理事件的view的onTouchEvent()返回了false,那麼該事件將被傳遞至其上一層次的view的onTouchEvent()處理。

  • 若是最終須要處理事件的view 的onTouchEvent()返回了true,那麼後續事件將能夠繼續傳遞給該view的onTouchEvent()處理。

  • group的touch和這個機制不要緊,與上一級有關係。

來自androidstarjack博客地址:

blog.csdn.net/androidstar…

若是你以爲此文對您有所幫助,歡迎入羣 QQ交流羣 :232203809   

微信公衆號:終端研發部

技術+職場
技術+職場

(歡迎關注學習和交流)

相關文章
相關標籤/搜索