touch事件的框架流程:
1 .分发流程
从Activity.dispatchTouchEvent开始 -> ... -> ViewGroup -> 子ViewGroup -> 子View
主要涉及的方法有 dispatchTouchEvent( 负责分发逻辑的处理) 和 onInterceptTouchEvent(ViewGroup类型的View是否进行事件的拦截 )
2.处理流程
子View -> 子ViewGroup -> ViewGroup -> Activity
处理主要在onTouchEvent方法中进行 , 返回值为true表示已经处理该事件 , 返回值为false表示事件并未消费
当前view并未处理事件时,那么就会将处理该事件的职责转交给上层的ViewGroup,如果都不会处理,那么最终就会在Activity的onTouchEvent方法进行处理
事件的分发和传递:
MotionEvent只是对触摸系列参数的一个封装, 将MotionEvent进行分发和传递的任务是View架构来完成的
事件的传递从由系统先传给Activity,由Activity的dispatchTouchEvent开始传递事件.
Activity -> Window -> DecorView -> ViewGroup -> ... -> View
分发核心的两个方法:dispatchTouchEvent 和 onInterceptTouchEvent
onInterceptTouchEvent只存在于ViewGroup中,当前的ViewGroup想拦截事件时onInterceptTouchEvent返回true,
那么事件不会再传入该ViewGroup的下层子View,而是在该ViewGroup的onTouchEvent方法中进行该事件的处理
那么View事件是怎样传递到Activity的呢?
这个就涉及到输入系统相关的内容
下面进行细节分析:
Activity 的构建分为 onCreate 和onResume 两个步骤
onCreate主要绑定window,设置监听回调
onResume 添加 DecorView 到 window
ActivityThread.handleResumeActivity -> Activity.makeVisible->PhoneWinodw.addView(decorView )->WindowManagerImpl.addView->WindowManagerGlobal.addView->ViewRootImpl.setView方法中注册输入通道,并建立监听
->WindowInputEventReceiver->enqueueInputEvent->doProcessInputEvents->deliverInputEvent->ViewPostImeInputStage.onProcess->processPointerEvent->mView.dispatchPointerEvent( 这个地方的mView就是启动activity时在创建PhoneWindow时创建的DecorView,Activity中的mDecor是ActivityThread.handleResumeActivity方法中直接将Window中的
DecorView赋值给了mDecor, 但是DecorView中没有重写View中的dispatchPointerEvent,所以直接调到dispatchPointerevent)->
View.dispatcuPointerEvent->DecorView.dispatchTouchEvent(这个方法在DecorView中重写了,那么这个时候必然回调到DecorView.dispatchToucheEvent)->Window.Callback.dispatchToucheEvent(这个地方的callback就是在Activity.attach中创建Phonewindow时设置的回调对象,即这个地方直接回调到->Activity.dispatchTouchEvent(这个时候开始了从activity层面的事件分发) ->
PhoneWindow.superDispatchTouchEvent->DecorView.superDispatchTouchEvent->ViewGroup.dispatchTouchEvent
)
2.1 关于ViewGroup.dispatchTouchEvent的简单分析
1)首先当是down时清理状态信息,然后如果是down或者存在事件消费者时,就根据disallowIntercept判断是否需要需要拦截
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
// disallowIntercept为true就是子view不想让parent拦截事件
if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0)) {
// 为true 说用当前的mGroupFlags已经是禁止拦截状态了
// We're already in this state, assume our ancestors are too
return;
}
// 如果disallowIntercept为true, mGroupFlags还不是FLAG_DISALLOW_INTERCEPT 那么就根据disallowIntercept
// 的值设置mGroupFlags变量的值
if (disallowIntercept) {
mGroupFlags |= FLAG_DISALLOW_INTERCEPT;
} else {
mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
}
// Pass it up to our parent
if (mParent != null) {
mParent.requestDisallowInterceptTouchEvent(disallowIntercept);
}
}
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
当前mGroupFlags的值被修改为了FLAG_DISALLOW_INTERCEPT ,那么disallowIntercept就为true,子view不希望parent拦截事件
disallowIntercept为false,那么当前子view没有想法,那么就调用onInterceptTouchEvent这个方法判断parent到底是拦截还是不拦截
if (!disallowIntercept) {
intercepted = onInterceptTouchEvent(ev);
ev.setAction(action); // restore action in case it was changed
} else {
intercepted = false;
}
intercepted 为true parent决定拦截 ; falseparent不拦截
2)当不是down , 并且也没有消费者存在时,就是parent直接进入拦截状态