话说:只要掌握了事件分发机制,就能找到好工作、升职加薪、当上总经理、出任ceo、迎娶白富美。
哈哈哈,不啰嗦,让我们开始。

三个重要的方法

和事件分发机制密切相关的三个方法分别是:

  • public boolean dispatchTouchEvent(MotionEvent ev)

用来进行事件的分发。如果事件能够传递到当前View,此方法一定会被调用,返回结果受当前View的onTouchEvent()和下级View的diapatchTouchEvent()方法的影响,表示是否消耗当前事件

  • public boolean onInterceptTouchEvent(MotionEvent event)

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

  • public boolean onTouchEvent(MotionEvent event)

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

三个方法之间的联系:

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

通过上面的伪代码,我们大致可以了解点击事件的传递规则:对于一个根ViewGroup来说,点击事件产生后,首先会传递给它,这是它的dispatchTouchEvent()就会被调用,如果这个ViewGroup的onInterceptTouchEvent()方法返回true就表示它要拦截当前事件,接着事件就会交给该ViewGroup处理,即执行onTouchEvent()方法。如果onInterceptTouchEvent()方法返回false就表示它不拦截该当前事件,这时事件就会继续传递给它的子元素,接着子元素的dispatchTouchEvent()就会被调用,如此反复,直到事件被处理。

一些结论(摘抄自《Android开发艺术探索》)

  1. 同一个事件序列是指从手指触摸屏幕的那一刻起,到手指离开屏幕那一刻结束,在这个过程中产生的一系列事件,这一系列事件以down事件开始,以up事件结束,中间可能有一些move事件。

  2. 正常情况下,一个事件序列只能被一个View拦截并消耗。

  3. 某个View一旦决定拦截,那么这一个事件序列都只能由它来处理(如果事件序列能够传递给它的话),并且它的onInterceptTouchEvent()不会再被调用。

  4. 某个View一旦开始处理事件,如果它不消耗ACTION_DOWN事件(onTouchEvent()返回了false),那么同一事件序列中的其他事件都不会再交给它处理,并且事件将重新交由它的父元素去处理,及父元素的onTouchEvent()会被调用。

  5. 如果View不消耗ACTON_DOWN以外的其他事件,那么这个点击事件会消失,此时父元素的onTouchEvent()并不会被调用,并且当前View可以持续收到后续的事件。最终这些消失的点击事件会传递给Activity处理。

  6. ViewGroup默认不拦截事件。onInterceptTouchEvent()方法默认返回false。

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

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

  9. View的enable属性不影响onTouchEvent()的默认返回值。哪怕一个View是disable状态的,只要它的clickable和longClickable有一个为true,那么它的onTouchEvent()就返回true。

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

  11. 事件传递的方向是由外向内的,即事件总是先传递给父元素,然后由父元素分发给子View。

  12. 当面对ACTION_DOWN事件时,ViewGroup总是会调用自己的onInterceptTouchEvent()方法来询问自己是否要拦截该事件。

  13. 当ACTION_UP方法发生时,会触发performClick()方法,如果View设置了onClickListener,那么performClick()方法内部会调用它的onClick()方法。

流程图

为了把事件分发机制研究明白,我画了一张流程图。

流程图地址

就到这里了。
如果有什么问题,大家可以在评论中提出来,我们一起讨论。
加油,各位!

本文来自:http://qiaoyunrui.github.io/2016/05/23/androidDispatchEvent/


居合子
39 声望5 粉丝

程序员中的小学生。