Android View事件分发

前段时间看了《Android开发艺术探索》,关于 Android 事件分发,写了一些笔记。
事件分发机制的伪代码。

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

return consume;
}

对于一个根 ViewGroup 来说,点击事件产生后,首先会传递给它,它的 dispatchTouchEvent 方法会被调用,如果这个 ViewGrouponInterceptTouchEvent 方法返回 true 则表示它要拦截此事件,事件就会交给它自己处理,即调用它的 onTouchEvent 方法;如果它的 onInterceptTouchEvent 方法返回 false 表示不会拦截这个事件,当前事件就会传递给它的子元素,子元素的 dispatchTouchEvent 方法会被调用,如此循环知道事件被处理。

当一个 View 需要处理事件时,如果它已经设置了 OnTouchListener,那么 OnTouchListener 中的 onTouch 方法会被回调,这是事件如何处理还要看 onTouch 的返回值,如果返回 true 则当前 ViewonTouchEvent 方法会被调用;如果返回 false ,那么 onTouchEvent 方法不会被调用。由此可见方法的优先级 onTouch > onTouchEvent > onClick

点击事件的传递过程遵循以下顺序:Activity -> Window -> View,即事件总是先传递给 ActivityActivity 再传递给 Window,最后再传递给顶级 View,顶级 View 接收到事件后,就会按照事件分发机制分发事件。

如果一个 ViewOnTouchEvent 方法返回 false,那么他的父容器的 OnTouchEvent 会被调用,以此类推。如果所有的元素都不处理这个事件,那么这个事件最终会传递给 Activity 处理。

注意:

  1. 同一个事件序列是指从手指接触屏幕的那一刻起,到手指离开屏幕的那一刻结束,在这个过程中产生的一系列事件,这个事件序列以 down 事件开始,中间含有数量不定的 move 事件,最终以 up事件结束。
  2. 正常情况下,一个事件序列只能被一个 View 拦截并消耗。因为一旦一个元素拦截了某事件,那么同一个序列内的所有事件都会直接交给他处理,因此同一个序列中的事件不能分别有两个 View 同时处理。但是通过特殊手段可以做到,比如一个 View 将本该有它处理的事件通过 OnTouchEvent 强行传递给其他 View 处理。
  3. 某个 View 一旦决定拦截,那么这一个事件序列都只能由它来处理(如果事件序列能够传递给它的话),并且它的 onInterceptTouchEvent 方法不会再被调用。
  4. 某个 View 一旦开始处理事件,如果它不消耗 ACTION_DOWN 事件,那么同一个事件序列里的其他事件都不会再交给他处理,并且事件将重新交由它的父元素去处理,即父元素的 onTouchEvent 方法会被调用。
  5. 如果 View 不消除掉 ACTION_DOWN 之外的其他事件,那么这个点击事件就会消失,此时父元素的 onTouchEvent 并不会被调用,并且当前 View 可以持续收到后续的事件,最终这些消失的点击事件会传递给 Activity 处理。
  6. ViewGroup 方法默认不拦截任何事件。Android 源码中 ViewGrouponInterceptTouchEvent 方法默认返回 false
  7. View 没有 onInterceptTouchEvent 方法,只有有子元素的元素才有。所以只要有点击事件传递给 View,就会调用它的 onTouchEvent 方法。
  8. ViewonTouchEvent 默认都会消耗事件,除非它是不可点击的。ViewlongClickable 属性默认都为 false
  9. Viewenable 属性不影响 onTouchEvent 的默认返回值。哪怕一个 Viewdisable 状态的,只要它的 clickablelongClickable 有一个为 true,那么它的 onTouchEvent 就返回 true
  10. onClick 发生的前提是当前 View 是可点击的。并且它收到了 downup 的事件。
  11. 事件传递过程是由外到内的,即事件总是先传递给父元素,然后再由父元素下发到子元素。

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×

keyboard_arrow_up 回到顶端