Touch事件分析(一)

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直接进入拦截状态

results for ""

    No results matching ""