事件分发拦截

  1. Activity、View、ViewGroup三者关系
    View控件的载体是Activity,Activity通过从DecorView开始进行绘制。

  2. 触摸事件类型
    -ACTION_DOWN:用户手指按下操作,往往也代表着一次触摸事件的开始。
    -ACTION_MOVE:用户手指在屏幕上移动,一般情况下的轻微移动都会触发一系列的移动事件。
    -ACTION_POINTER_DOWN:额外的手指按下操作。
    -ACTION_POINTER_UP:额外的手指的离开操作
    -ACTION_UP:用户手指离开屏幕的操作,一次抬起操作标志着一次触摸事件的结束。
    在一次屏幕触摸操作中,ACTION_DOWN和ACTION_UP是必需的,ACTION_MOVE则是看情况而定,如果只是点击,那么检测到只有按下和抬起操作。

  3. 事件传递三个阶段
    -分发(Dispatch):事件的分发对应着dispatchTouchEvent方法,在Andorid系统中,所有的触摸事件都是通过这个方法来分发的。
    boolean dispatchTouchEvent (MotionEvent ev)
    这个方法中,可以决定直接消费这个事件或者将事件继续分发给子视图处理。
    -拦截(Intercept):事件拦截对应着onInterceptTouchEvent方法,这个方法只有在ViewGroup及其子类中才存在,在View和Activity中是不存在的。
    boolean onInterceptTouchEvent (MotionEvent ev)
    这个方法用来判断是否拦截某个事件,如果拦截了某个事件,那么在同一序列事件当中,那么这个方法不会被再次调用。
    -消费(Consume):事件消费对应着onTouchEvent方法。
    boolean onTouchEvent (MotionEvent event)
    用来处理点击事件,返回结果表示是否消耗当前事件,如果不消耗,则在同一事件序列中,当前View无法再接收到事件

  4. 在Android系统中,拥有事件传递处理能力的有三种
    -Activity:拥有dispatchTouchEvent、onTouchEvent两个方法。
    -ViewGroup:拥有dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent三个方法。
    -View:拥有dispatchTouchEvent、onTouchEvent两个方法。

  5. View事件传递机制

  6. ViewGroup事件传递机制

  7. 用三张图来表示Android中触摸机制的流程

  • View内触摸事件不消费
事件分发拦截_第1张图片
View内触摸事件不消费.png
  • View内触摸事件消费
事件分发拦截_第2张图片
View内触摸事件消费.png
  • ViewGroup拦截触摸事件


    事件分发拦截_第3张图片
    ViewGroup拦截触摸事件.png

参考:初识Android触摸事件传递机制


  1. 常见的滑动冲突场景可以简单分为以下三种:
    场景1:外部滑动方向和内部滑动方向不一致
    场景2:外部滑动方向和内部滑动方向一致
    场景3:上面两种情况的嵌套

  2. 滑动冲突的处理规则
    *对于场景1,它的处理规则就是:当用户左右滑动时,需要让外部的View拦截点击事件,当用户上下滑动,需要让内部View拦截点击事件。具体来说就是根据滑动是水平滑动还是竖直滑动来判断到底是由谁来拦截事件。
    简单来说,就是根据水平方向和竖直方向的距离差来判断,如果是Dx>Dy,那么则是水平滑动,如果是Dy>Dx,那么则是竖直滑动。
    *场景2,则是比较特殊,它无法根据滑动的角度,距离差以及速度差来做判断。这个时候就需要从业务上找到突破点,比如,当处于某种状态时需要外部View响应用户的滑动,而处于另外一种状态时需要内部View来响应View的滑动

  • 外部拦截法
    重写父容器的onInterceptTouchEvent方法
    首先ACTION_DOWN这个事件,父容器必须返回false,这样保证后续move和up的事件可以传递给子View,根据move事件来决定是否拦截,如果父容器拦截就返回true,否则返回false。
    这个情况的拦截条件就是父容器在滑动过程中水平距离差比垂直距离差大,那么就进行拦截,否则就不拦截,继续传递事件。
  • 内部拦截法
    内部拦截法是指父容器不拦截任何事件,所有的事件都传递给子元素,如果子元素需要此事件就直接消耗掉,否则就交给父容器进行处理,这种方法和Android中的事件分发机制不一致,需要配合requestDisallowInterceptTouchEvent方法才能正常工作,使用起来较外部拦截法复杂

参考 :Android触摸事件的应用

你可能感兴趣的:(事件分发拦截)