View点击事件对的事件分发其实就是对MontionEvent事件的分发过程,即当一个MotionEvent产生了以后,系统需要把这个时间传递给一个具体的View,而这个传递的过程就是分发过程。其中三个很重要的方法:dispatchTouchEvent(进行事件的分发)、onInterceptTouchEvent(判断是否拦截某个事件,ViewGroup才有,View没有)、onTouchEvent(处理点击时间,返回值为是否消耗当前事件)
三个方法的大致伪代码关系:
关系具体分析:
Activity-ViewGroup
ViewGroup.dispatchTouchEvent(ev) View.dispatchTouchEvent(ev) 1、对于一个根ViewGroup,点击事件产生后,首先会传递给它,这时他的dispatchTouchEvent会调用,如果它的onInterceptTouchEvent返回true表示要拦截当前事件,接下来事件会交给这个ViewGroup处理,它的onTouchEvent就会被调用,如果这个ViewGroup的onInterceptTouchEvent返回false,则事件会继续传递给子元素,子元素的dispatchTouchEvent会调用,如此反复直到事件被处理。流程图如下 根ViewGroup事件传递.png
2、当一个View需要处理事件时,如果设置了OnTouchListener,那么OnTouchListener的onTouch方法会回调,如果onTouch返回false,则当前View的onTouchEvent方法会被调用;如果返回true,那么onTouchEvent方法将不会调用。由此可见,OnTouchListener优先级高于onTouchEvent。OnClickListener优先级处在事件传递的尾端。
3、一个点击事件产生后,传递顺序:Activity->Window->View;如果一个View的onTouchEvent返回false,那么它的父容器的onTouchEvent会被调用,以此类推,所有元素都不处理该事件,最终将传递给Activity处理,即Activity的onTouchEvent会被调用。流程图如下 点击事件传递顺序.png4、同一个事件序列是指从手指触摸屏幕那一刻开始,到手指离开屏幕那一刻(down->move...move->up)
5、一个事件序列只能被一个View拦截且消耗,同一个事件序列所有事件都会直接交给它处理,并且它的onInterceptTouchEvent不会再被调用。
6、某个View一旦开始处理事件,如果它不消耗ACTION_DOWN(onTouchEvent返回了false),那么同一事件序列中其他事件都不会再交给它来处理,事件将重新交给他的父元素处理,即父元素的onTouchEvent会被调用。
7、如果某个View不消耗除ACTION_DOWN以外的其他事件,那么这个点击事件会消失,此时父元素的onTouchEvent并不会被调用,并且当前View可以收到后续事件,最终这些消失的点击事件会传递给Activity处理
8、ViewGroup默认不拦截任何事件,ViewGroup的onInterceptTouchEvent方法默认返回false。
9、View没有onInterceptTouchEvent方法,一旦有事件传递给它,那么它的onTouchEvent方法就会被调用。
10、View的onTouchEvent方法默认消耗事件(返回true),除非他是不可点击的(clickable和longClickable同时为false)。View的longClickable属性默认都为false,clickable属性分情况,Button默认为true,TextView默认为false。
11、onClick发生的前提是View可点击,并且它收到了down和up事件。
12、事件传递过程是由内而外,事件总是先传递给父元素,然后在由父元素分发给子View,通过requestDisallowInterceptTouchEvent方法可以在子元素干预父元素的事件分发过程,但ACTION_DOWN事件除外。
网友评论