前言: java
通常咱們處理事件,都是針對某一個View來處理了,要麼是添加onTouchListener監聽器,要麼繼承View而後重寫View#onTouchEvent, android
甚至不用重寫,只要使用Widget本身的監聽函數 ,或者GestureDetector就OK了. ide
可是理解Android事件模型,對於理解GestureDetector,及Android事件的交互,寫出具備出色的交互的應用. 函數
都是必經之路. this
一:ViewGroup與View的事件模型 spa
咱們都知道Android界面實際是一棵View的樹.枝幹是ViewGroup. code
ViewGroup繼承自View,可是又是管理View的容器.那麼ViewGroup與View的事件關係是怎麼樣的呢? orm
這須要從另外一個重要的ViewGroup中的方法,以下提及: 繼承
public boolean onInterceptTouchEvent(MotionEvent ev) { return false; }它的默認實現很簡單,就是把事件交給子View去處理.本身不攔截.
Intercept就是攔截的意思. 事件
此方法的註釋,對於ViewGroup與View的事件模型說得很清楚,
主要是如下幾點:
(1) 若是此方法返回false,說明此ViewGroup暫時(只是暫時)對於觸控事件不感興趣.
可是不知道後面的事件它感不感興趣.因此後續事件還會一直傳遞到此方法中來,供此方法判斷.
(2) 若是此方法返回true了.那麼說明此方法對應的ViewGroup開始對於此事件(或者手勢)感興趣了.
那麼後續事件就會直接給此方法對應的ViewGroup的onTouchEvent方法來處理事件了.
(3) 若是此方法一開始返回false,說不感興趣這個時候事件發給了目錄View.
如今又返回true,說感興趣了.那麼目錄View就會收到一個action爲ACTION_CANCEL的事件.
跟此方法返回true時的事件是同一個事件 ,只是action變了.
(4) ViewGroup會在這裏接收觸控開始的事件.
規則就是上面這些 ,那麼是誰在後面處理這些規則呢?
就是ViewGroup.它在disptachTouchEvent方法中,進行了一系列的處理來實現這種模型.
public boolean dispatchTouchEvent(MotionEvent ev)
對於單獨的View自己來講,它也有一個簡單的事件派發模型.經過如下代碼就能夠很明白的看出來了:
View#dispatchTouchEvent(MotionEvent event):
ListenerInfo li = mListenerInfo; if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnTouchListener.onTouch(this, event)) { return true; } if (onTouchEvent(event)) { return true; }
二: Activity與View的事件模型
事件先到Activity中,而後Activity調用:
/** * Called to process touch screen events. You can override this to * intercept all touch screen events before they are dispatched to the * window. Be sure to call this implementation for touch screen events * that should be handled normally. * * @param ev The touch screen event. * * @return boolean Return true if this event was consumed. */ public boolean dispatchTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { onUserInteraction(); } if (getWindow().superDispatchTouchEvent(ev)) { return true; } return onTouchEvent(ev); }來分發事件, 這裏的邏輯是:
先讓用戶界面窗口處理:getWindow().superDispatchTouchEvent(ev)
若是窗口沒有處理這個事件.
那就交給Activity本身處理.return onTouchEvent(ev)
這個Window跟View層級是怎麼交互的呢?
咱們找到了Window的實現類:PhoneWindow(com.android.internal.policy.impl.PhoneWindow)
@Override public boolean superDispatchTouchEvent(MotionEvent event) { return mDecor.superDispatchTouchEvent(event); }
這個mDecor就是用戶界面的根View了.
private final class DecorView extends FrameLayout
(com.android.internal.policy.impl.PhoneWindow.DecorView)
原來窗口將事件交給根View來進行事件派發的.
mDecor調用本身的superDispatchTouchEvent(event)
而後將事件派發的任務交給了本身的dispatchTouchEvent
public boolean superDispatchTouchEvent(MotionEvent event) { return super.dispatchTouchEvent(event); }這裏調用的super.dispatchTouchEvent 就是ViewGroup的聲明的dispatchTouchEvent的了.