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)的链接)

相关文章
相关标签/搜索