Android View的事件分发机制

阅读《Android开发艺术探索》提炼实践总结

所谓事件分发?

     所谓点击事件分发,其实就是对MotionEvent事件的分发过程,即当一个MotionEvent产生了以后,系统需要把这个事件传递给一个具体的View,而这个传递的过程就是分发过程。

点击事件的分发过程有三个很重要的方法来共同完成!

dispatchTouchEvent(MotionEvent ev)

用于事件的分发。如果事件能够传递给当前View,那么此方法一定会被调用,返回结果受当前View的onTouchEvent和下级View的dispatchTouchEvent方法的影响,表示是否消耗当前事件。

onInterceptTouchEvent(MotionEvent event)

View没有这个方法,Activity也没有,只有ViewGroup才有

在dispatchTouchEvent方法中调用,用来判断是否拦截摸一个事件,如果当前View拦截了某个事件,那么在同一个事件序列当中,此方法不会被再次调用,返回结果表示是否拦截当前事件。

onTouchEvent(MotionEvent event)

在dispatchTouchEvent方法中调用,用来处理点击事件,返回结果表示是否消耗当前事件,如果不消耗,则在同一个事件序列中,当前View无法再次接收到事件。

这三个方法的关系时什么呢?

     我超级喜欢下面的伪代码,将关系道的淋漓尽致

public boolean dispatchTouchEvent(MotionEvent ev) {
  boolean consume = false;
  if (onInterceptTouchEvent(ev)) {
      consume = onTouchEvent(ev);
  } else {
      consume = child.dispatchTouchEvent(ev);
  }
  return consume;
}

一些需要注意的小tips:

  1. 传递机制:Activity->Window->View,即事件总时先传递给Activity,Activity在传递给Window,最后Window在传递给顶级View,顶级View接收到事件后,就会按照事件分发机制去分发事件。
  2. 如果所有的元素都不处理这个事件,那么这个事件最后将会传递给Activity,即Activity的onTouchEvent方法会被调用。
  3. ViewGroup默认不拦截任何事件。
  4. View的onTouchEvent默认都会消耗事件(返回true),除非它是不可点击的(clickable和longClickable同时为false)。View的longClickable属性默认都为false,clickable属性要分情况,比如Button的clickable属性默认为true,TextView的clickable属性默认为false。
  5. View的enable(作用时设置其是否可用)属性不影响onTouchEvent的默认返回值。
  6.  事件传递过程时由外向内的,即事件总是传递给父元素,然后在由父元素分发给子View,通过requestDisallowInterceptTouchEvent方法可以在子元素中干预父元素的事件分发过程,但是ACTION_DOWN事件除外。

相关推荐