Touch事件消息流:
线程Looper收到Touch 消息
1、ViewRootImpl(Handler).dispatchMessage(Message)
feature phone 的MMI_Task 一样
2、ViewRootImpl.handleMessage(Message) case PROCESS_INPUT_EVENTS
3、ViewRootImpl.processInputEvents(boolean)
过滤无效事件
4、ViewRootImpl.handleMessage(Message) case DISPATCH_POINTER
5、ViewRootImpl.deliverPointerEvent(MotionEvent, boolean)
6、发送PointerEvent到View Tree (View Hierarchy)
View Tree 的Root收到该消息调用View dispatchPointerEvent(MotionEvent)不能重写。
dispatchPointerEvent比较简单,贴出代码
if (event.isTouchEvent()) {
returndispatchTouchEvent(event);
}else {
returndispatchGenericMotionEvent(event);
}
7、View Tree 的Root 调用dispatchTouchEvent(event)
如果目标为ViewGroup,比较重要的有几个过程:
1、4.0 为保持Touch事件的一致性,每次Down事件的时候,会清空前一次的状态。即保持Down->Move->Up的消息顺序,不可能出现Down->Move->Down。注:2.3是直接丢弃Down事件。
2、对于onInterceptTouchEvent的调用,这是上层应用重写onInterceptTouchEvent,来截获事件的实现。Return true 截获事件,往自己的OnTouchEvent发送该事件,return false不截获,具体参见android文档。当然并不是每个都能截获的,如果FLAG_DISALLOW_INTERCEPT被置位的话,是不能被截获的。一般发生这种情况的主要是系统有比较重要的事件通知整棵View树。
3、层层遍历,将Touch事件发送到叶子节点,然后根据返回值决定是否,让其他节点处理Touch事件,return true 该事件处理到此结束,return false继续处理
如果目标为View。那它只能为叶子节点,因为它不能包含任何View。一些关键的处理如下
if (li != null &&li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) ==ENABLED && li.mOnTouchListener.onTouch(this, event)) {
return true;
}
if (onTouchEvent(event)) {
return true;
}
这段话主要的意思就是如果这个View设置了OnTouchListener那么调用接口OnTouch,然后consume掉这个事件,即不再继续处理。如果没有的话,调用自己的OnTouchEvent。
举个例子,一个白板的View,没有设置TouchListener也没有重写OnTouchEvent,那么这个View就直接调用View的OnTouchEvent,View的OnTouchEvent实现如下:
代码太长,翻成文字可以这么理解:
如果该View 是disable 状态:那么给它加上pressed标志位,重绘一下(在屏幕上显示为灰显按下去的效果)
如果该View不是disable状态,并且是clickable,那么在ACTION_DOWN的时候会加上pressed标志位,并启动一个timer(长按事件)。重绘一下(显示出按下去的效果)。
此时还是MOVE事件监视该View的状态,如果这个MOVE滑出了该View的范围,那么会复位View的click状态。UP事件时,会检查是否已经执行过LongPress,如果已经执行了LongPress,那么就不执行了Click,反之,会取消掉LongPress的Timer,然后在执行Click。
在UP事件的最后,做一下收尾处理,完事。
所以TouchEvent是Click 和 LongPress的底层实现,View的派生类如Button等等就不需要重写OnTouchEvent。