Android MotionEvent事件分发


直接上图,清晰明了,图片来自这里。


触摸屏幕后产生MotionEvent对象
Android MotionEvent事件分发_第1张图片

疑问

onTouchEvent()onclick()方法有什么关系?

假设用户点击了一个按钮,系统会调用Button所继承View类的dispatchTouchEvent()方法。

下面是View的部分源码,还可以看到有注册OnTouchListenerOnClickListener监听器的set方法:

public class View implements ... {
	...
	public boolean dispatchTouchEvent(MotionEvent ev) {
		if (mOnTouchListener != null 
				&& (mViewFlags & ENABLED_MASK) == ENABLED 
				&& mOnTouchListener.onTouch(this, event)) {
	        return true;
	    }
	    return onTouchEvent(event);
	}

	public void setOnTouchListener(OnTouchListener l) {
	    mOnTouchListener = l;
	}

	public void setOnClickListener(@Nullable OnClickListener l) {
		if (!isClickable()) {
			setClickable(true);
		}
		getListenerInfo().mOnClickListener = l;
    }
    ...
}

dispatchTouchEvent()方法里:

  • 第一个条件mOnTouchListener正是在setOnTouchListener方法里赋值的,也就是说只要我们给控件注册了touch事件,mOnTouchListener就一定被赋值了。

  • 第二个条件(mViewFlags & ENABLED_MASK) == ENABLED是判断当前点击的控件是否是enable的,按钮默认都是enable的,因此这个条件恒定为true。

  • 第三个条件就是回调第一个条件里的mOnTouchListeneronTouch(this, event)方法,也就是说如果我们在onTouch方法里返回true,就会让这三个条件全部成立,从而整个方法直接返回true

而我们在onTouch方法里返回false,就会再去执行onTouchEvent(event)方法。

// onTouchEvent()中有个performClick()方法
public boolean performClick() {
    sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
    if (mOnClickListener != null) {
        playSoundEffect(SoundEffectConstants.CLICK);
        mOnClickListener.onClick(this); <---
        return true;
    }
    return false;
}

一切都是那么清楚了!当我们通过调用setOnClickListener方法来给控件注册一个点击事件时,就会给mOnClickListener赋值。然后每当控件被点击时,都会调用performClick()方法里回调被点击控件的onClick方法。

onTouchEvent()先于onClick()执行:

  • 如果onTouchEvent()返回true,表示事件已经被消费,则onClick()不会执行
  • 如果onTouchEvent()返回true,表示事件没有被消费,则onClick()将会执行

如需参看更多源码解析,前往:

参考
Android事件分发机制完全解析,带你从源码的角度彻底理解 - 郭霖
通俗理解Android事件分发与消费机制

你可能感兴趣的:(Android)