探究View的事件分发
关注点:dispatchTouchEvent
、onInterceptTouchEvent
、onTouchEvent
ViewGroup继承View,包含view,当我们点击view的时候,究竟怎么向上传递事件的呢?
1.触发点击View.setOnClickListener()
if (!isClickable()) {
setClickable(true);
}
getListenerInfo().mOnClickListener = l;
View持有一个监听事件组ListenerInfo添加事件,点击传递的是MotionEvent 对象
2.DispatchTouchEvent开始事件传递
public boolean dispatchTouchEvent(MotionEvent event) { ... boolean result = false; 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; } }
... return result; }
首先判断是否有设置touch事件及view是否为enable,恒定为true,当onTouch事件返回true时,dispatchTouchEvent返回true,该事件被消费。
由此可以确定OnTouchListener事件优先级较高。当OnTouch返回false时,事件进入onTouchEvent判断
3.OnTouchEvent
public boolean onTouchEvent(MotionEvent event) {
...
当(viewFlags & CLICKABLE) == CLICKABLE 即view不可用返回true,虽然有设置点击事件,但是不可用,确定为消费。if ((viewFlags & ENABLED_MASK) == DISABLED) { if (event.getAction() == 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)); }... if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) { switch (event.getAction()) { case MotionEvent.ACTION_UP: if (!focusTaken) { if (mPerformClick == null) { mPerformClick = new PerformClick(); } if (!post(mPerformClick)) { performClick(); } } } break; ...... } return true; } return false;}
performClick确定最后是否消费
4.performClick
public boolean performClick() { final boolean result; final ListenerInfo li = mListenerInfo; if (li != null && li.mOnClickListener != null) { playSoundEffect(SoundEffectConstants.CLICK); li.mOnClickListener.onClick(this); result = true; } else { result = false; } sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); return result; }
回调onClick方法