Android事件传递机制

Android里面的事件传递机制是一个非常重要内容,是开发者必须要掌握的知识点

什么是事件传递?

当我们手指触摸屏幕时,会产生一系列的触摸事件,必须要将每一个事件传递给一个具体的View处理,这个传递过程就是事件传递。

当触摸事件产生后,会首先传递到Activity,然后通过Window传递给DecorView,再由DecoreView传递给我们的View

事件传递机制涉及到View的三个方法:

dispatchTouchEvent,onInterceptTouchEvent,onTouchEvent

dispatchTouchEvent
表示事件分发给了View,如果触摸事件能够到达该View,那么此方法一定会被调用,返回值表示是否消耗此事件,返回值受子View的dispatchTouchEventonTouchEvent影响。

onInterceptTouchEvent
用于拦截事件,返回值表示是否拦截此事件,在dispatchTouchEvent方法内部调用。如果拦截此事件,那么后续同一事件序列的事件到来时,此方法将不会再被调用,默认拦截。
普通View非ViewGroup)没有此方法。
ViewGroup默认不拦截,返回false

onTouchEvent
用于处理事件,返回值表示是否消耗此事件,在dispatchTouchEvent中被调用,普通View默认消耗事件,返回true
(1)如果开始处理事件时,不消耗ACTION_DOWN事件,那么同一事件序列中的后续事件都不会交给此View处理。然后会回调父ViewonTouchEvent方法,如果父View消耗ACTION_DOWN事件,那么同一事件序列的后续事件都会交给父View处理;如果父View不消耗ACTION_DOWN事件,会在ActivityonTouchEvent中处理ACTION_DOWN事件,并且同一事件序列的后续事件都会在ActivityonTouchEvent中处理。
(2)如果开始处理事件时,消耗了ACTION_DOWN事件,那么同一事件序列的后续事件仍会交给此View处理,未消耗的触摸事件会消失,会在ActivityonTouchEvent中处理,

下面一段伪代码能够很清楚的描述这三个方法的调用逻辑

public boolean dispatchTouchEvent(MotionEvent event) {
	boolean isConsume = false;
	if (onInterceptTouchEvent(event)) {
		isConsume = onTouchEvent(event);
	} else {
		isConsume = false;
		childView.dispatchTouchEvent(MotionEvent event);
	}
	return isConsume;

解决滑动冲突

理解了这三个方法的具体调用逻辑,我们可以用来处理滑动冲突,处理滑动冲突主要有两种方法:外部拦截法和内部拦截法。

(1)外部拦截法
只需要重写外部ViewGroup的onInterceptTouchEvent既可

	@Override
	public boolean onInterceptTouchEvent(MotionEvent event) {
		Log.i("zb123", "CustomViewGroup onInterceptTouchEvent " + event.getAction());
		boolean isIntercept = false;
		switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN:
				isIntercept = false;
				break;
			case MotionEvent.ACTION_MOVE:
				if (父View需要拦截) {
					isIntercept = true;
				} else {
					isIntercept = false;
				}
				break;
			case MotionEvent.ACTION_UP:
				isIntercept = false;
				break;
		}
		return isIntercept;
	}

(2)内部拦截法
需要重写外部ViewGroup的onInterceptTouchEvent和内部View的dispatchTouchEvent

外部ViewGroup

	@Override
	public boolean onInterceptTouchEvent(MotionEvent event) {
		boolean isIntercept = false;
		if (event.getAction() == MotionEvent.ACTION_DOWN) {
			isIntercept = false;
		} else {
			isIntercept = true;
		}
		return isIntercept;
	}
内部View

	@Override
	public boolean dispatchTouchEvent(MotionEvent event) {
		switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN:
				getParent().requestDisallowInterceptTouchEvent(true);
				break;
			case MotionEvent.ACTION_MOVE:
				if (内部View不需要拦截) {
					getParent().requestDisallowInterceptTouchEvent(false);
				}
				break;
		}
		return super.dispatchTouchEvent(event);
	}

你可能感兴趣的:(Android,View,事件分发机制)