美文网首页
Android部分事件分发机制篇

Android部分事件分发机制篇

作者: 大佬不是大佬 | 来源:发表于2019-07-26 21:38 被阅读0次

    可以结合另一篇源码分析:Android事件分发机制的源码分析。 - 简书

    1、为什么有事件分发机制?

    屏幕上的View可能会重叠在一起,当有多个View可以响应点击事件,要用事件分发机制解决这问题。

    2、事件分发相关知识

    2.1事件分发究竟是什么?

    2.1.1 MotionEvent

    当用户点击屏幕里View或者ViewGroup的时候,将会产生一个事件对象,这个事件对象就是MotionEvent对象(事件的类型,触摸的位置,以及触摸的时间)。

    MotionEvent的值有:

    MotionEvent.ACTION_DOWN:用户触摸View&ViewGroup。

    MotionEvent.ACTION_MOVE:用户手指移动View&ViewGroup。

    MotionEvent.ACTION_UP:用户手指离开屏幕。

    MotionEvent.ACTION_CANCEL:事件退出了,不是用户导致的。

    MotionEvent.ACTION_CANCEL是什么?

    当控件收到前驱事件之后,如果后面事件被父控件拦截,那么当前当前控件会收到 CANCEL事件,并且把这个事件会传递给它的子事件。

    产生的条件:

    父View收到ACTION_DOWN,如果没有拦截事件,则ACTION_DOWN前驱事件被子View接收,父View后续事件会发送到子View。

    如果在父View中拦截ACTION_UP或ACTION_MOVE,在第一次父View拦截消息的瞬间,父View指定子View不接受后续消息了,

    同时子View会收到ACTION_CANCEL事件。

    2.1.2 事件分发的本质(定义)

    本质将点击屏幕产生的MotionEvent对象传递到某个具体的View然后处理消耗这个事件的整个过程。

    2.1.3 事件怎么产生&事件分发产生的事件在哪些对象之间传递

    用户触摸,滑动,离开屏幕时,这个时候就产生了事件,Android系统将事件封装为MotionEvent对象(事件的类型,事件触发的时间,以及触摸在屏幕的哪个位置等)。

    MotionEvent对象在哪些对象之间传递呢?Activity&ViewGroup&View。

    2.1.4 三个重要的有关事件分发的方法

    1)dispatchTouchEvent

    -> 若此 View接受到事件,此方法一定被调用。返回结果受此 View的onTouchEvent和下级的dispatchTouchEvent方法影响,表示是否消耗此事件。

    2)onInterceptTouchEvent(只有 ViewGroup有。)

    -> 在上述方法dispatchTouchEvent内部调用,用来判断是否拦截某个事件。

      当前View拦截了某个事件,此方法不会被再次调用,返回结果表示是否拦截当前事件。

    3)onTouchEvent

    -> 在dispatchTouchEvent内部调用,用来处理点击事件,返回结果表示是否消耗当前事件,

      如果不消耗,当前View无法再次接收到事件。

    大致逻辑流程(伪代码):

    public boolean dispatchTouchEvent(MotionEvent ev){

    boolean consume = false;//记录返回值

    if(onInterceptTouchEvent(ev)){//判断是否拦截此事件

    consume = onTouchEvent(ev);//如果当前确认拦截此事件,那么就处理这个事件

    }else{

    consume = child.dispatchToucnEvent(ev);//如果当前确认不拦截此事件,那么就将事件分发给下一级

    }

    return consume;

    }

    小结:

      从 ViewGroupA开始,点击事件产生,A.dispatchTouch()被调用。

    -> 情况1:要拦截,A.onInterceptTouchEvent()返回true。 A.onTouchEvent()然后被调用,自己处理。

    -> 情况2:不拦截,A.onInterceptTouchEvent()返回false。调用子View.dispatchTouchEvent()再进行一样的判断。

    View处理事件伪代码:

    View.OnTouchListener() {

    boolean result; //记录返回值

    if(onTouch()){

    View.onTouchEvent()不调用。

    }else{

    View.onTouchEvent()调用。

    }

        }

    在onTouchEvent()中,若设置onClickListener则,onClick()也会被调用。

    传递过程:Activity–>Window–>View,View在按照事件分发机制分发事件。如果最底端的 View.onTouchEvent()返回false,则

      回调上一层的 onTouchEvent(),最终会返回给 Activity。

    注意:

    1)正常情况,一个事件只被一个 View拦截消耗。如果硬要两个 View去处理,在ViewA的.onTouchEvent()强行传递给ViewB处理。

    2)某 View决定拦截,onInterceptTouchEvent()不会被调用。

    3)某 View开始处理事件,如果不消耗 ACTION_DOWN事件(onTouchEvent返回了false),那么同一序列中的事件都不会再给它处理了。

    4)View不消耗ACTION_DOWN以外的事件,那么这个点击事件会消失,此时父元素的onTouchEvent并不会调用,并且当前View可以持续收到后续的事件,

      最终这些消失的点击事件会传递给Activity处理。

    5)ViewGroup默认不拦截任何事件。Android源码中ViewGroup的onInterceptTouchEvent方法默认返回false。

    6)View没有onInterceptTouchEvent方法,一旦点击事件传递给它,那么它的onTouchEvent方法就会被调用。

    7)View的onTouchEvent默认消耗事件(返回true),除非它是不可点击的(clickable和longClickable同时为false)。

      View的longClickable属性默认为false,clickable属性要分情况,比如Button的clickable属性默认为true,而TextView的clickable属性默认为false。

    8)onClick会发生的前提是当前View是可点击的,并且它接收到了down和up事件。

    9)事件传递由父->子,子通过 requestDisallowInterTouchEvent方法可以在子元素中干预父元素的事件分发过程,但是ACTION_DOWN事件除外。

    参考网址:

    https://blog.csdn.net/ClAndEllen/article/details/79365369

    https://blog.csdn.net/vansbelove/article/details/78416791

    https://www.jianshu.com/p/e99b5e8bd67b

    https://www.jianshu.com/p/8bc0765dffc9

    https://www.cnblogs.com/Claire6649/p/5947139.html

    https://blog.csdn.net/mydreamongo/article/details/30465613

    上的

    相关文章

      网友评论

          本文标题:Android部分事件分发机制篇

          本文链接:https://www.haomeiwen.com/subject/mfmfrctx.html