1. View的事件分发小结参考CSDN
- dispatchTouchEvent
- 每一次触摸会触发View的dispatchTouchEvent事件,若非enable跳过
- 检测touchlistener,如果enable调用(有可能被true阻截后续onTouchEvent)。
- 否则return onTouchEvent(event),返回值如果是false,那么下一次action就不分发了。
- onTouchEvent
- 如果不是enable的,那么return clickable || longClickable
- 如果有TouchDelegate,那么调用TouchDelegate.onTouchEvent(有可能被true阻截后续switch)
- 如果是clickable || longClickable,那么switch做动作
- ACTION_DOWN, 带上prepressed标签,开始计算按下延时
- ACTION_MOVE, 检测是不是move到view外面了,如果是停止相应pressed状态,否则啥都不干
- ACTION_CANCEL, 停止相应press状态
- ACTION_UP, 该次触摸结束,触发focus或者click或者longclick
- 如果不是clickable,不是long clickable,不是enable,那么return false,终结返回。
2. ViewGroup的事件分发小结参考CSDN
- dispatchTouchEvent (非直接继承view)
- ACTION_DOWN, 重置targetView,使用onInterceptTouchEvent判断是否拦截
- 如果不拦截的话,先序遍历child,找在点击范围内的child,递归调用child.dispatchTouchEvent(),如果返回true表示找到了targetView,return true打断后续。
- 如果拦截的话,后续当没有targetView处理。
- 没有targetView,把自己当做view来当做点击自己super.dispatchTouchEvent(ev)
- 有targetView,再看一下自己拦不拦截motionEvent,不拦截直接调用target.dispatchTouchEvent()
- onInerceptTouchEvent
- 如果返回true,自己被当成了一个view(viewGroup性质终结)。那么这里收不到后续的events了,直接被投递到自己的onTouchEvent,原有的target view都会收到同样的events,但是action是cancel。
- 如果返回false,自己被当成了一个viewGroup,后续的event都会经过这再被传递到target view。
3. 总结
step 1 屏幕接受到触摸事件,是从root控件的dispatchTouchEvent开始的。
-
step 1.5 如果控件是viewGroup,那么判断调用onInerceptTouchEvent是否拦截
- 如果拦截,那么把自己当成一个view来处理,进入step 2。
- 否则递归调用点击范围内的子控件dispatchTouchEvent,相当于在step1-1.5之间递归循环,直到碰到一个"普通的view"或者一个"表示拦截的viewGroup"。
step 2 总有一个控件以view的身份来接受这个事件,那么开始检测是否有touchListener,如果有调用它。
step 3 最终调用onTouchEvent
注意:事件分发中有一个target view概念,如果在ACTION_DOWN的过程中递归确定下来了要消费的那个view,那么UP/MOVE事件都不会再递归了,直接就找到那个view了。