一、View事件分发
先看看这几种现象View与Touch事件相关的两个方法
1.1 dispatchTouchEvent事件分发
源码中,首先将result = false;
boolean result = false;
再拿到ListenerInfo, 存放了关于View的所有Listener信息如 OnTouchListener 、OnClickListener等
ListenerInfo li = mListenerInfo;
若onTouchListener.onTouch()返回true,则result置为true;
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnTouchListener != null
&& (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {
result = true;
}
再往下看, 如果 result = false 就会执行onTouchEvent; 如果result = true 就不会执行onTouchEven,这里就解释了,会先执行onTouchListener中的方法。
if (!result && onTouchEvent(event)) {
result = true;
}
目前还未看到有点击事件onClick(),进入到onTouchEvent()中,
case MotionEvent.ACTION_UP: 里面调用了 performClick()
switch (action) {
case MotionEvent.ACTION_UP:
//.....其他代码省略
if (mPerformClick == null) {
mPerformClick = new PerformClick();
}
if (!post(mPerformClick)) {
performClickInternal();
}
所以当onTouchEvent()返回true时,不会执行onClick(),又或者说只有当调用了onTouchEvent的super()方法时,才会执行onClcik().
因为onClick()方法是在View.onTouchEvent的super()方法中。
二、ViewGroup事件分发
**dispatchTouchEvent() **事件分发:
boolean handled = false;
final int action = ev.getAction();
final int actionMasked = action & MotionEvent.ACTION_MASK;
在ACTION_DOWN事件中,先将TouchTargets 清除,
并且将mFirstTouchTarget = null
if (actionMasked == MotionEvent.ACTION_DOWN) {
// 清除TouchTargets 只要知道 mFirstTouchTarget = null
cancelAndClearTouchTargets(ev);
resetTouchState();
}
再到onInterceptTouchEvent()事件,正常情况返回false;
onInterceptTouchEvent()返回false时,反序获取子View,执行子View的dispatchTouchEvent()方法;onInterceptTouchEvent()返回true时,将不执行子view的方法。
//是否拦截
final boolean intercepted;
if (actionMasked == MotionEvent.ACTION_DOWN
|| mFirstTouchTarget != null) {
//子类是否请求拦截
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
if (!disallowIntercept) {
//正常情况下,会走到onInterceptTouchEvent()中
intercepted = onInterceptTouchEvent(ev);
ev.setAction(action);
} else {
intercepted = false;
}
} else {
intercepted = true;
}
if (!canceled && !intercepted) {
if (newTouchTarget == null && childrenCount != 0) {
for (int i = childrenCount - 1; i >= 0; i--) {
// 反序的for循环 获取子 View child,执行子类的dispatchTouchEvent
//这里如果子类没有一个地方返回true,默认是返回false,则不会进入判断
if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
// 如果子 View 返回true 就会进来 主要给 mFirstTouchTarget = target;
// 这种情况,move和up事件进来的时候,不会调用子view 的dispatchTouchEvent事件。
// 最后调用到自己的dispatchTouchEvent事件,也就是ViewGroup的。
newTouchTarget = addTouchTarget(child, idBitsToAssign);
break;
三、总结
最后贴个图总结下
网友评论