何止学习Android事件分发机制

一、安卓UI层级

image.png

Activity的结构为:Activity -> PhoneWindow -> DecorView -> ContentView -> ... -> View

二、安卓UI事件分发流程

1.安卓UI的View是树形结构的,基于这样的结构,事件可以进行有序的分发。

事件收集之后最先传递给 Activity, 然后依次向下传递。根据Activity的内部结构也可以看出,事件分发的流程:Activity -> PhoneWindow -> DecorView -> ContentView -> ... -> View。如果View没有消费事件,则会回传。流程如下:View-> ... ->ContentView -> DecorView -> PhoneWindow ->Activity。

总体流程来说,整个流程是遵循责任链模式。上层View既可以直接拦截该事件,自己处理,也可以先询问(分发给)子View,如果子View需要就交给子View处理,如果子View不需要还能继续交给上层View处理。既保证了事件的有序性,又非常的灵活。

2.事件分发、拦截与消费

image.png

这三个方法,通过返回 true 和 false 来控制事件传递的流程.
三个方法:
dispatchTouchEvent(事件分发)
onInterceptTouchEvent(事件拦截)
onTouchEvent(事件回传:从View开始,逐级回传)

三、实战

1.创建安卓工程,布局如下




    

        

    

    


2.布局结构图如下:

image.png

3.触发事件分析:

按下view1,不放开

事件分发流程如下:
MainActivity: dispatchTouchEvent ->
RootView: dispatchTouchEvent ->
RootView: onInterceptTouchEvent ->
ViewGroupA: dispatchTouchEvent->
ViewGroupA: onInterceptTouchEvent->
View1: dispatchTouchEvent->
View1: onTouchEvent->
ViewGroupA: onTouchEvent->
RootView: onTouchEvent->
MainActivity: onTouchEvent->


image.png

按下view1后,放开

image.png

事件分发流程如下:
MainActivity: dispatchTouchEvent ->
RootView: dispatchTouchEvent ->
RootView: onInterceptTouchEvent ->
ViewGroupA: dispatchTouchEvent->
ViewGroupA: onInterceptTouchEvent->
View1: dispatchTouchEvent->
View1: onTouchEvent->
ViewGroupA: onTouchEvent->
RootView: onTouchEvent->
MainActivity: onTouchEvent->
MainActivity: dispatchTouchEvent (Action:ACTION_UP)->
MainActivity: onTouchEvent (Action:ACTION_UP)
注意:MotionEvent. ACTION_UP事件在MotionEvent.ACTION_DOWN结束后触发。

在RootView增加事件(MotionEvent.ACTION_DOWN)拦截,按下view1后,放开

  @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.d(TAG,"onInterceptTouchEvent Action:"+MotionEvent.actionToString(ev.getAction()));
        if (ev.getAction() == MotionEvent.ACTION_DOWN){
            return true;
        }else {
            return super.onInterceptTouchEvent(ev);
        }

    }
image.png

从打印结果来看,(MotionEvent.ACTION_DOWN)事件不再往下传,在RootView接收到后回传给MainActivity。

注意:onInterceptTouchEvent() 返回true表示拦截、返回false表示不拦截,不拦截时,跟正常的流程一样。

四、View 事件相关的各个方法调用顺序

onTouchListener > onTouchEvent > onLongClickListener > onClickListener

1、onTouchEvent返回true时,代表消费事件,则事件不回传。

image.png

2、onTouchEvent返回false时,代表没有消费事件,则事件回传。

image.png

五、核心要点

事件分发原理: 责任链模式,事件层层传递,直到被消费。
View 的 dispatchTouchEvent 主要用于调度自身的监听器和 onTouchEvent。
View的事件的调度顺序是 onTouchListener > onTouchEvent > onLongClickListener > onClickListener 。
不论 View 自身是否注册点击事件,只要 View 是可点击的就会消费事件。
事件是否被消费由返回值决定,true 表示消费,false 表示不消费,与是否使用了事件无关。
ViewGroup 中可能有多个 ChildView 时,将事件分配给包含点击位置的 ChildView。
ViewGroup 和 ChildView 同时注册了事件监听器(onClick等),由 ChildView 消费。
一次触摸流程中产生事件应被同一 View 消费,全部接收或者全部拒绝。
只要接受 ACTION_DOWN 就意味着接受所有的事件,拒绝 ACTION_DOWN 则不会收到后续内容。
如果当前正在处理的事件被上层 View 拦截,会收到一个 ACTION_CANCEL,后续事件不会再传递过来。

你可能感兴趣的:(何止学习Android事件分发机制)