Android View事件传递详解

Android View事件传递

期待与大家共同进步,若有错误请指出,谢谢~

blog
github
简书

事件

View传递事件仅指用户在手机屏幕上的手势操作,即MotionEvent。其中,最常使用的为ACTION_DOWN(按下手指)、ACTION_MOVE(移动手指)、ACTION_UP(抬起手指)。每个Event事件都是以ACTION_DOWN开始、ACTION_UP结束。Android的UI展示领域可以理解为万物皆View(ViewGroup是一种特殊的View),View事件传递的核心依赖于View的三个方法:

  • dispatchTouchEvent,传递事件(true被该对象消费、false其他消费)
  • onInterceptTouchEvent,拦截事件(true拦截、false传递)
  • onTouchEvent,消费事件(true消费、false不消费)

其中View只有dispatchTouchEvent事件,没有onInterceptTouchEvent事件,View的dispatchTouchEvent返回值为true,则代表该View将处理该TouchEvent事件。而Activity也是没有onInterceptTouchEvent,通过dispatchTouchEvent,如果返回true则代表该touchEvent被消费掉,不继续传递。

传递

  1. 事件由Activity.dispatchTouchEvent开始传递,只要没有被停止或拦截,从最上层的 View(ViewGroup)开始一直往下(子View)传递,直至到有被View的onInterceptTouchEvent函数拦截。
  2. 被拦截后,如果没有被进行拦截的View通过onTouchEvent消费掉,事件会反向向上传递,不需要拦截,直接通过onTouchEvent进行消费。如果没有被消费掉,则直至传递到Activity的onTouchEvent。
  3. 如果View没有对ACTION_DOWN进行消费,之后的其他事件不会传递过来。
  4. OnTouchListener优先于onTouchEvent()对事件进行消费。

使用onTouchEvent的返回值来判断是否该事件被消费掉,返回true代表该事件被该View消费,并且后续的ACTION_MOVE等操作无需判断拦截等,直接传递给该View进行处理,直至传入ACTION_UP事件。返回false代表该事件并未被拦截,通过上述逻辑继续传递事件。

实例

假设布局从外到内依次为Layout0、1、2、3
无拦截情况:事件传递过程为0 —> 1 —> 2 —> 3 —> 2 —> 1 —> 0
2拦截2消费:事件传递过程为0 —> 1 —> 2(消费掉)
2拦截3消费:事件传递过程为0 —> 1 —> 2 —> 1 —> 0 (未被消费,ActionDown后续事件不传递)
2拦截1消费:事件传递过程为0 —> 1 —> 2 —> 1(消费掉)

总结

通过该View传递机制(拦截-消费),可以巧妙组合实现较为特殊的效果。比如,若要实现类似于30s没有用户触摸屏幕则自动触发某事件,则可以通过override该Activity的dispatchTouchEvent进行倒计时操作(如果已开始计时,则需要取消掉当前计时)。熟悉了Android中View传递机制,目前认为在项目中的帮助主要为2点:

  1. 解决事件冲突,如横向滑动、纵向滑动以及不同引用第三方控件导致的用户滑动效果异常等
  2. 实现特殊需求,主要为拦截事件与消费事件的View非同一个,或者说需要触发其他方法,如上述的倒计时功能。由于用户的TouchEvent只能消费一次,需要程序自己设计触发额外的方法(事件)。

ThanksTo

    原文作者:HaKu
    原文地址: https://www.jianshu.com/p/8e6d54e0275f
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞