Android onTouch事件分发记录

71 阅读2分钟

事件触发接收后到View(ViewGroup)流程:

View.java -> 只处理事件(dispatchTounchEvent)
ViewGroup.java -> 容器分发事件 (dispatchTounchEvent)

setView()函数(ViewRootImpl.java)</br>
--> inputChannel = new InputChannel();
 //接收 输入事件 (初始化 事件接收)
 --> mInputEventReceiver = new WindowInputEventReceiver(inputChannel,Looper.myLooper());
  --> onInputEvent(InputEvent event) (WindowInputEventReceiver.java 是 ViewRootImpl 的内部类)
   --> enqueueInputEvent()
       // enqueueInputEvent 最后一个参数传入的true
    --> doProcessInputEvents();
     --> deliverInputEvent(q)
      --> stage.deliver(q); //(InputStage.java -> ViewPostImeInputStage.java)
       --> onProcess(QueuedInputEvent q)
        --> processPointerEvent(q);
        //mView == DecorView
         --> mView.dispatchPointerEvent(event);
          --> dispatchPointerEvent(event)//( 由于DecorView 没有是实现方法,所以也就到了View 的此方法)
           --> dispatchTouchEvent(event)//然后再到了 DecorView, 同时 此方法处理了与Activity 关联

/*
这是DecorView 的 dispatchTouchEvent 方法 
mWindow = PhoneWindow
cb = Activity 
然后就到了 Activity 的 dispatchTouchEvent 方法
*/
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    final Window.Callback cb = mWindow.getCallback();
    return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
            ? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
}

getWindow().superDispatchTouchEvent(ev)(Activity.java)
    //PhoneWindow 的 方法
 --> mDecor.superDispatchTouchEvent(event);
      //DecorView 的 superDispatchTouchEvent 方法
  --> super.dispatchTouchEvent(event);
      //由于 DecorView 自己没有处理方法 所以就转父亲 处理,FramLayout 并没有实现这个方法就继续向上走
   --> ViewGroup的 dispatchTouchEvent() 方法
 

事件处理:

1.onTouch 与 onClick 执行顺序 和 关系

setOnTouchListener(OnTouchListener listener){
    return true or false;
}

setOnClick(View view)

由上面 Touch 事件接收流程看出:
当点击 控件View 时 会到 View 中的 dispatchTouchEvent这个方法:
dispatchTouchEvent(MotionEvent event)(View.java)
    // ListenerInfo 类的这个方法 处理OnTouch 回调
 --> li.mOnTouchListener.onTouch(this, event)
 
分发后会执行
onTouchEvent(MotionEvent event)(View.java)
    // 点击手指抬起后 (MotionEvent.ACTION_UP ),才会执行OnClick 方法
 --> mPerformClick = new PerformClick()
  --> performClickInternal() 
       //调用到 onClick
   --> li.mOnClickListener.onClick(this);

当点击时 OnTouchListener 先执行

//如下 当 onTouch 返回false 是 result = false
//如果 OnTouch 返回True 是 result = true, 这是就不能回调 OnClick 事件,所以二者是冲突关系的
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnTouchListener != null
        && (mViewFlags & ENABLED_MASK) == ENABLED
        && li.mOnTouchListener.onTouch(this, event)) {
    result = true;
}

if (!result && onTouchEvent(event)) {
    result = true;
}

执行onClick 事件执行后表示事件消费了

2.onTouchEvent 在哪儿执行?
3.LongClick 执行?
onTouchEvent(MotionEvent event)(View.java)
    //MotionEvent.ACTION_DOWN 长按时调用方法
    /*
    ***注意 长按 LongClick,触发时间 在29 时 500ms, 30以后是 400ms***
    TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS 延迟的时间
    */
    --> checkForLongClick(
        ViewConfiguration.getLongPressTimeout(),
        x,
        y,
        TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS);

此时 是一个延迟操作,如果延迟没有达到时间(比如 500ms),那么就会移除长按时间变成 短按事件

4.按下View,移动手指,为什么 onClick 执行?
//手指按下 并且移动时, 移动到控件外不执行OnClick 事件
onTouchEvent(MotionEvent event)(View.java)
        // 因为手指一动 需要看 Move 状态
        /*
        pointInView(x, y, touchSlop) 判断是否在控件上
        */
    -->if (!pointInView(x, y, touchSlop)) {
        // Outside button
        // Remove any future long press/tap checks
        removeTapCallback();//
        removeLongPressCallback();
        if ((mPrivateFlags & PFLAG_PRESSED) != 0) {
            //设置后  onTouchEvent()方法中的MotionEvent.ACTION_UP 条件下(mPrivateFlags & PFLAG_PREPRESSED) != 0; 不满足
            setPressed(false);
        }
        mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN;
    }