Android事件分发机制
(一)点击事件的传递规则
所谓的点击事件分发其实就是MotionEvent事件的分发,即当一个MotionEvent产生之后,系统需要把这个事件传递给具体的View,而这个事件传递过程就是事件分发,点击事件分发过程由三个很重要的方法来完成:
public boolean dispatchTouchEvent()
用来进行事件分发,如果事件能够传递给当前View,那么此方法一定会被调用,返回结果受当前View的onTouchEvent和下级的dispatcheTouchEvent方法的影响,表示当前事件是否被消费
public boolean onInterceptTouchEvent()
在上述方法中调用,用来判断是否拦截某个事件,如果当前View拦截了某个事件,那么在同一个事件序列当中,此方法不会被再次调用,返回结果表示事件是否拦截
public boolean onTouchEvent()
在dispatchTouchEvent方法中调用,用来 处理点击事件,返回结果表示是否消费事件,如果不消耗,则在同一个事件序列中,当前View无法再次接收到事件
上述方法有什么区别呢?我们采用伪代码来体现
public boolean dispatchTouchEvent(MotionEvent ev) {
boolean consume = false;
if (onInterceptTouchEvent(ev)) {
consume = onTouchEvent(ev);
} else {
consume = child.dispatchTouchEvent(ev);
}
return consume;
}
即在一次事件分发的过程中,判断当前view(viewGroup)是否拦截,如果拦截,则交给onTouchEvent进行处理,如果不拦截,则交给子view的dispatchTouchEvent处理,至此完成一轮事件的分发。
通过上面代码我们已经将三个方法的关系体现的酣畅淋漓,我们也可以对事件传递的规则有一个明确的认知,对于一个根ViewGroup来说:产生事件后首先传递它,这时dispatchTouchEvent 会调用ViewGroup的ViewGroup的onInterceptTouchEvent返回true就表示拦截当前事件,接着事件会交给ViewGroup处理,即onTouchEvent会被调用ViewGroup的onInterceptTouchEvent返回false表示不拦截事件,这个事件会传递给子元素,接着子元素的dispatchTouchEvent会被调用.
Touch事件分发图
(二)事件分发总结
1.同一个事件序列是从手指接触屏幕那一刻开始,到手指离开屏幕那一刻结束。
2.正常情况下,一个事件序列只能被一个View拦截且消耗
3.某个View一旦决定拦截,那么这个事件序列只能它来处理,它的onInterceptTouchEvent不会再被调用
4.某个View一旦开始,如果它不消耗ACTION_DOWN 事件即onTouchEvent返回来false,那么同一事件序列中的其它事件都不会再交给它来处理。
5.如果不消耗ACTION_DOWN以外的事件,那么这个点击事件会消失,此时父元素的onTouchEvent并不会被调用,并且当前View回持续收到后续事件,最后这些消失的事件会传递个给Activity处理
6.ViewGroup默认不拦截事件onInterceptTouchEvent默认返回fakse
7.View 没有onInterceptTouchEvent,一旦事件传递给View,onTouchEvent就会被调用
8.View的onTouchEvent默认消耗事件,返回true,除非它不可点击 clickable和longClickable同时为false;View的longClickable默认未false,clickable要分情况;
9.View的enable属性不影响onTouchEvent的默认值返回。
10.onClick 会发生的前提是当前View是可点的,并收到down 和up 事件
11.事件传递过程是由外向内的,事件总是先传递给父元素再由父元素分发给子元素。
12.事件传递:activity > Window > view