View的事件分发机制总结

来源:互联网 发布:js皮肤哪个好 编辑:程序博客网 时间:2024/06/05 16:02

事件的传递规则:

对于一个根ViewGroup来说,点击事件产生后,首先会传递给它,这时它的dispatchTouchEvent就会被调用,如果这个ViewGroup的onInterceptTouchEvent方法返回true就表示它要拦截当前事件,接着事件就会交给这个ViewGroup处理,即它的onTouchEvent方法就会被调用:如果这个ViewGroup的onInterceptTouchEvent方法返回false就表示它不拦截当前事件,这时当前事件就会继续传递给它的子元素,接着子元素的dispatchTouchEvent方法就会被调用,如此反复直到事件被最终处理。当一个点击事件产生以后,他的传递过程遵循如下顺序:  Activity -> Window -> View

点击事件的分发过程由三个很重要的方法共同完成:
(1)public boolean dispatchTouchEvent(MotionEvent ev)

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

(2)public boolean onInterceptTouchEvent(MotionEvent ev)

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

(3)public boolean onTouchEvent(MotionEvent ev)

    在dispatchTouchEvent方法内部调用,用来处理点击事件,返回结果表示是否消耗当前事件,如果不消耗,则在同一个事件序列号中,当前的View无法再次接收到事件。关于事件传递机制的一些结论:  (1)同一个事件序列是指从手指接触屏幕的那一刻起,到手指离开屏幕的那一刻结束,在这个过程中所产生的一系列事件,这个事件序列以down事件开始,中间含有数量不定的move事件,最终以up事件结束。  (2)正常情况下,一个事件序列只能被一个View拦截且消耗。因为一旦一个元素拦截了此事件,那么同一个事件序列的所有事件都会直接交给它处理,因此同一个事件序列中的事件不能分别由两个View同时处理,但是通过特殊的手段可以做到,比如,一个View将本该自己处理的事件通过onTouchEvent强行传递给其他View处理  (3)某个View一旦决定拦截,那么这一个事件序列都只能由它来处理,并且它的onInterceptTouchEvent不会再调用了。  (4)某个View一旦开始处理事件,如果它不消耗ACTION_DOWN事件(onTouchEvent返回了false),那么同一事件序列中的其他事件都不会再交给其他来处理,并且事件将重新交由它的父元素去处理。  (5)如果View不消耗除ACTION_DOWN以外的其他事件,那么这个点击事件会消失,此时父元素的onTouchEvent并不会被调用,并且当前的View可以持续受到后续的事件,最终这些消失的点击事件会传递给Activity处理。  (6)ViewGroup默认不拦截任何事件,Android源码中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,通过requestDisableInterceptTouchEvent方法可以在子元素中干预父元素的事件分发过程,但是ACTION_DOWN事件除外。

内容来自:《Android开发艺术探索》——任玉刚

0 0