几行代码看懂android View的事件传递机制(视图逻辑)

本文详细解析了Android中View和ViewGroup的触摸事件分发机制,包括dispatchTouchEvent、onTouchEvent和onInterceptTouchEvent等关键方法的工作流程,以及如何处理事件的拦截与传递。
/**
 * View的事件分发
 */
public class View{

	public boolean dispatchTouchEvent(MotionEvent ev){
		boolean result = false;

		// 先判断是否设置了onTouchListener,如果设置了,就调用
		if (mOnTouchListener != null && mOnTouchListener.onTouch(ev)) {
			result = true;
		}

		// 如果没有设置onTouchListener,或者调用了onTouch后返回了false,那么就调用onTouchEvent
		if (!result && onTouchEvent(ev)) {
			result = true;
		}
		return result;
	}

	public boolean onTouchEvent(MotionEvent ev){

		// 如果View可点击
		if (isClickable()) {
			switch (ev.getAction()) {
				...
				case MotionEvent.ACTION_UP:
					...
					// 判断是否设置了onClickListener,设置了就调用,并消耗事件
					if (mOnClickListener != null) {
						mOnClickListener.onClick(this);
					}
					...
					break;
				...
			}
			// 可点击的View,默认会消耗掉事件
			return true;
		}
		// 不可点击的View,默认不消耗事件
		return false;
	}
}



/**
 * ViewGroup的事件分发
 */
public class ViewGroup extends View{

	// 一旦有子元素消耗了事件,这个子元素就被赋值给mFirstTouchTarget
	public View mFirstTouchTarget = null;

	public boolean dispatchTouchEvent(MotionEvent ev){
		int action = ev.getAction();
		boolean handled = false;
		boolean intercepted;

		// DOWN事件,或者有子元素消耗事件,则进入if语句内,判断是否拦截
		if (action == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) {
			// 取出 是否允许拦截 的标记,默认是false。子元素可以通过requestDisallowInterceptTouchEvent(true);将这个标记设置为true
			boolean disallow = getFlagDisallowIntercept();

			if (!disallow) {
				// 允许拦截,调用onInterceptTouchEvent判断是否拦截
				intercepted = onInterceptTouchEvent(ev);
			}else {
				// 不允许拦截,直接不拦截
				intercepted = false;
			}
		}else {
			// 非DOWN事件,或者没有子元素消耗了事件,直接拦截
			intercepted = true;
		}

		// 如果有子元素消耗事件,alreadyDispatched就被赋值为true
		boolean alreadyDispatched = false;

		if (!intercepted) {
			// 不拦截事件

			// 遍历子元素
			for (int i = 0 ; i < mChildList().size() ; i++) {
				View child = mChildList.get(i);
				float x = ev.getX();
				float y = ev.getY();

				if (x >= child.left && x <= child.right && y >= child.top && y <= child.bottom) {
					// 事件位于子元素所在区域内,将事件分发给子元素

					if (child.dispatchTouchEvent(ev)) {
						// 子元素消耗了事件

						mFirstTouchTarget = child;
						alreadyDispatched = true;

						// 跳出循环,不再分发
						break;
					}
				}
				
			}
		}

		if (mFirstTouchTarget == null) {
			// 没有子元素消耗事件
			// ViewGroup自行处理事件
			super.dispatchTouchEvent(ev);
			
		}else {
			// 有子元素消耗了事件,则后续事件全部交给该子元素处理,不管他是否消耗事件
			if (alreadyDispatched) {
				mFirstTouchTarget.dispatchTouchEvent(ev);
				handled = true;
			}
		}

		return handled;
	}

	public boolean onTouchEvent(MotionEvent ev){
		super.onTouchEvent(ev);
	}

	public boolean onInterceptTouchEvent(MotionEvent ev){
		return false;
	}
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值