同事今天问了一个问题 view设置了onClickListener Activity 中设置了 onTouchEvent 为什么 onTouchEvent 不执行,如果不设置就能执行,所以为了回答这个问题,特意看了源码,解决这个问题

###总结流程

boolean consume = false;
public dispatchTouchEvent(MotionEvent event){
      if(onInterceptEvent(event){
              consume = onTouchEvent(event);
      }else{
            consume = child.dispatchTouchEvent(event);
  }  
  return consume;
}

###事件分发方向

  • 事件的分发方向是从activity中开始的,从activity中的dispatchTouchevent开始
Activity 源码
public boolean dispatchTouchEvent(MotionEvent ev) {    if (ev.getAction() == MotionEvent.ACTION_DOWN) {        onUserInteraction();    }    if (getWindow().superDispatchTouchEvent(ev)) {        return true;    }    return onTouchEvent(ev);}

方法中调用了
getWindow().superDispatchTouchEvent(ev)
并且如果返回true  activity的dispatchtouchevent 也返回true意味着子view消费了此事件,如果返回false 调用onTouchEvent 方法。
getWindow 当然是调用的 PhoneWindow 的方法,进入此方法

public boolean superDispatchTouchEvent(MotionEvent event) {    return mDecor.superDispatchTouchEvent(event);}
由此可见调用了 decorview 的方法,decorview 是视图view的根,

而decorview 调用的是父类FrameLayout 的dispatchTouchEvent 所以在activity中分析到这里可以得出以下结论

  • activity 中的dispatchtouchevent 返回false 才会 调用 ontouchevent ,也就是说没有view消费事件。
  • 当给decorview 中的子view 设置了onclicklistener ,没有执行ontouchevent 可以退出 dispatchtouch返回的是true,也就是说子view 消费了相关事件。

    View 事件分发

  • 事件的传递从activity到decorview 最终到当前view。
  • 必然也是首先执行的是view 的dispatchtouchevent
  • view 的dispatchTouchevent 代码相对简单,如果说最终activity 要执行 activity的onTouchEvent 也就是view dispathtouchevent 必然返回false ,所以此时与返回true相关的判断条件都不会执行
if (onFilterTouchEventForSecurity(event)) {    //noinspection SimplifiableIfStatement    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;    }}
  • 从以上源码可以看出,有两个条件可以得到 返回 true,在第一个条件的
li.mOnTouchListener.onTouch(this, event)

可以看出没有设置onTouchListener 所以这里必然是为false 的所以,只能是第二个条件成立才会 dispatchTouchEvent 返回true, 而这里是 onTouchEvent 返回true 才会得到true;

  • 现在把目光注视到 view 的onTouchEvent 中,从源码中可以看出总共有三处代码可能返回true,
第一处
if ((viewFlags & ENABLED_MASK) == DISABLED) {    if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) {        setPressed(false);    }    // A disabled view that is clickable still consumes the touch    // events, it just doesn't respond to them.    return (((viewFlags & CLICKABLE) == CLICKABLE            || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)            || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE);}
第二处
if (mTouchDelegate != null) {    if (mTouchDelegate.onTouchEvent(event)) {        return true;    }}
第三处
if (((viewFlags & CLICKABLE) == CLICKABLE ||        (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) ||        (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) 

从结果上看第三处是我们所需要的,代码也是在这里执行的,当然现在我们锁需要明白的是这三行判断条件。’

  • 当调用 view的setOnClickListener 的时候查看源码
public void setOnClickListener(@Nullable OnClickListener l) {    if (!isClickable()) {        setClickable(true);    }    getListenerInfo().mOnClickListener = l;}

从源码中可以看出,主要调用setClickable方法

public void setClickable(boolean clickable) {    setFlags(clickable ? CLICKABLE : 0, CLICKABLE);}
setflags 方法
mViewFlags = (mViewFlags & ~mask) | (flags & mask);

通过逻辑运算可以得出 ontouchevent 条件符合所以返回true,从而view dispatchtouchevent 返回true,从而activity 中dispatchtouchevent 返回true ⤧  Next post http基础知识 ⤧  Previous post Handler,Message,MessageQueue,Looper简析