Android 事件分發 簡單學

本文地址:https://my.oschina.net/lifj/blog/1928132java

Android 事件分發過程

網上有不少這樣的文章,我又寫了一篇,但願可以清晰明瞭的告訴你們總體的事件分發過程,而不是一臉懵逼的進來,一臉懵逼的出去。android

三個事件

  • dispatchTouchEvent (View 和 ViewGroup都有)
  • onInterceptTouchEvent(只有ViewGroup有
  • onTouchEvent(View 和 ViewGroup都有)

事件的調用流程圖

從上圖能夠看到:dispatchTouchEvent的返回值多是由兩部分決定的:自身的touchEvent返回值,或者子view的dispatchTouchEvent的返回值。app

總體分發思路 -- 僞代碼

/*
 * 事件分發的僞代碼
 */
public class Layout extends ViewGroup{
    private View targetChild = null;//記錄DOWN事件找到的目標view,做爲後續事件的分發對象。
    public boolean dispatchTouchEvent(MotionEvent event){

        if(this instanceof ViewGroup){
            //DOWN的時候targetChild爲null。其餘後續事件不爲null。
            if(targetChild != null){
                //MOVE,UP,CANCEL等事件直接dispatch過去。
                return targetChild.dispatchTouchEvent(event);
            }

            //DOWN的時候會走如下邏輯
            boolean interceptRet = this.onInterceptTouchEvent(event);
            if(interceptRet == true){
                //攔截,調用自身的onTouchEvent,並返回
               return this.onTouchEvent(event);
            }else if(interceptRet == false){
                //不攔截,遍歷子View
                for(int i = 0 ;i< getChildCount();i++){
                    targetChild = getChildAt(i); //判斷是否是目標View
                    if(targetChild.dispatchTouchEvent(event)){
                        //dispatchTouchEvent返回true,說明是。並返回
                        return true;
                    }else{
                        //不然不是
                        targetChild = null;
                    }
                }
                //沒有找到targetView,調用自身的TouchEvent,並返回
                if(targetChild == null){
                    return this.onTouchEvent(event);
                }
            }
        }else if(this instanceof View){
            //View直接走本身的onTouchEvent
            return this.onTouchEvent(event);
        }

        return false;
    }

}

各自的做用

dispatchTouchEvent: 對於ViewGroup來講:根據onInterceptTouchEvent的返回值,決定調用自身的onTouchEvent仍是分發到子view裏面。 對於View來講:直接調用onTouchEvent。oop

onInterceptTouchEvent: 告訴dispatchTouchEvent是否是須要分發下去(也就是被攔截)this

onTouchEvent: 自身的處理spa

Down 與其餘事件

Down事件的特殊之處

Down事件做爲Event的第一個事件,擔任的重任就是找到須要處理Event的控件。若是Down分發一遍以後沒有找到須要處理事件,那麼這個消息就不會再傳到這些View(ViewGroup)中了。 怎麼知道沒有控件去處理呢?就是經過dispatchTouchEvent的返回值判斷的: 返回false,說明沒有view須要處理事件。 返回true,說明有View須要處理。對於View,就是本身須要處理。對於ViewGroup,多是子View須要處理,也多是本身須要處理。.net

當返回true以後,ViewGroup中會記錄須要處理的View的對象,做爲targetChild。不然的話targetChild爲null。code

其餘事件

根據Down事件的返回結果,返回false的話,後續其餘的事件都不會分發下來。對象

返回true的狀況,第一個調用的仍是dispatchTouchEvent,上一次Down事件記錄了targetChild,那麼就會直接調用targetChild的dispatchTouchEvent。如此調用下去,直到return true。blog

事件的來源

android.os.Looper.loop(Looper.java:136) 取出消息
InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185)
android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6188)
android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3859)
android.view.View.dispatchPointerEvent(View.java:10244)
android.app.Activity.dispatchTouchEvent(Activity.java:3065)
com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1808)
com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:416)
android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2264)

也就是說:事件會被放到Activity的Looper中。 而後從Looper中取出,傳給ViewRootImpl,入隊。 ViewRootImpl中的deliver去傳遞事件給View,給Activity,給DocerView. (啓動Activity會建立ViewRootImpl和PhoneWindow,創建起與WMS(window manager service)的鏈接)

相關文章
相關標籤/搜索