[关闭]
@946898963 2020-01-06T07:35:19.000000Z 字数 2005 阅读 704

View的事件分发机制

Android绘图


下面一段伪代码展示了点击事件的传递规则:

  1. public boolean dispatchTouchEvent (MotionEvent ev){
  2. boolean consume = false;
  3. if (onInterceptTouchEvnet(ev){
  4. consume = onTouchEvent(ev);
  5. } else {
  6. consume = child.dispatchTouchEnvet(ev);
  7. }
  8. return consume;
  9. }

上面代码主要涉及到以下三个方法:
public boolean dispatchTouchEvent(MotionEvent ev)
这个方法用来进行事件的分发,返回结果表示是否消耗事件。返回结果受onTouchEvent和下级View的dispatchTouchEvent影响。
public boolean onInterceptTouchEvent(MotionEvent ev)
这个方法用来判断是否拦截事件,返回结果表示是否拦截事件。如果当前View拦截了事件,那么在同一个事件序列中,当前方法不会被调用。
public boolean onTouchEvent(MotionEvent ev)
这个方法用来处理点击事件,返回结果表示是否消耗这个点击事件,返回true表示消耗,返回false,表示不消耗,如果不消耗,则在同一个事件序列中,当前的View无法在此接收到事件。

点击事件的传递规则:对于一个根ViewGroup,点击事件产生后,首先会传递给他,这时候就会调用他的dispatchTouchEvent方法,如果Viewgroup的onInterceptTouchEvent方法返回true表示他要拦截事件,接下来事件就会交给ViewGroup处理,调用ViewGroup的onTouchEvent方法;如果ViewGroup的onInteceptTouchEvent方法返回值为false,表示ViewGroup不拦截该事件,这时事件就传递给他的子View,接下来调用子View的dispatchTouchEvent方法,如此反复直到事件被最终处理。

当一个View需要处理事件时,如果它设置了OnTouchListener,那么他的OnTouchListener的onTouch方法会被调用,如果onTouch返回false,则当前View的onTouchEvent方法会被调用,如果onTouch返回true则当前View的onTouchEvent方法不会被调用。在onTouchEvent方法中,如果当前设置的有OnClickListener,那么他的onClick方法会被调用,可以看出,平时我们常用的OnClickListener的优先级最低,处于事件传递体系的末尾。由此可见处理事件时的优先级关系: onTouchListener > onTouchEvent > onClickListener。

关于事件传递的机制,这里给出一些结论:

  1. 一个事件系列以down事件开始,中间包含数量不定的move事件,最终以up事件结束。
  2. 正常情况下,一个事件序列只能由一个View拦截并消耗。
  3. 某个View拦截了事件后,该事件序列只能由它去处理,并且它的onInterceptTouchEvent不会再被调用。
  4. 某个View一旦开始处理事件,如果它不消耗ACTION_DOWN事件(onTouchEvnet返回false),那么同一事件序列中的其他事件都不会交给他处理,并且事件将重新交由他的父元素去处理,即父元素的onTouchEvent被调用。
  5. 如果View不消耗ACTION_DOWN以外的其他事件,那么这个事件将会消失,此时父元素的onTouchEvent并不会被调用,并且当前View可以持续收到后续的事件,最终消失的点击事件会传递给Activity去处理。
  6. ViewGroup默认不拦截任何事件。
  7. View没有onInterceptTouchEvent方法,一旦事件传递给它,它的onTouchEvent方法会被调用。
  8. View的onTouchEvent默认消耗事件,除非他是不可点击的(clickable和longClickable同时为false)。
  9. View的enable不影响onTouchEvent的默认返回值,那怕一个View是disable状态的,只要他的clickable或者longclickable有一个为true,那么它的onTouchEvent就返回true。
  10. onClick会发生的前提是当前View是可点击的,并且收到了down和up事件。
  11. 事件传递过程总是由外向内的,即事件总是先传递给父元素,然后由父元素分发给子View,通过requestDisallowInterceptTouchEvent方法可以在子元素中干预父元素的分发过程,但是ACTION_DOWN事件除外。
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注