Android 事件分发机制

概述

这里的事件指的是 View 对手势的响应,这里的手势包含四种

事件说明
ACTION_DOWN手指初次触摸屏幕时触发
ACTION_MOVE手指在屏幕滑动时触发,会多次触发
ACTION_UP手指离开屏幕时触发
ACTION_CANCEL事件被上层拦截时触发

一次 ACTION_DOWN --> ACTION_UP 流程称为一次事件

一次事件的消费 View 只有一个

事件分发过程的主要方法:

dispatchTouchEvent ()

onInterceptTouchEvent ()

onTouchEvent ()

View

分别用 true、false 来表示是否对当前事件进行分发成功、拦截、消费操作,而是否分发成功取决事件是否被消费,是否被消费取决于事件是否被拦截,所以说 dispatchTouchEvent 的执行结果取决于 onInterceptTouchEventonTouchEvent 的共同作用

所以事件的分发过程中,以上方法的执行顺序(当前 ViewGroup)dispatchTouchEvent --> onInterceptTouchEvent --> onTouchEvent

一个事件的具体传递顺序,我们通过 log 来展示:

以下为 Activity 嵌套 ViewGroup 嵌套 View 的组合
在这里插入图片描述
以上为经典的事件不消费流程:

  1. Activity 调用 ViewGroup 的 dispatchTouchEvent,ViewGroup 开始对事件进行处理
  2. 本身的 onInterceptTouchEvent 开始执行,看本身是否需要进行拦截,返回结果不拦截
  3. 那么调用子 View 的 dispatchTouchEvent,View 的 dispatchTouchEvent 开始执行
  4. 子 View 没有拦截事件,直接进入 onTouchEvent 开始执行
  5. onTouchEvent 不消费
  6. 子 View 的 dispatchTouchEvent 方法执行完毕,分发不成功返回 false
  7. ViewGroup 的 dispatchTouchEvent 方法执行完毕,分发不成功返回 false
    在这里插入图片描述
    log展示经典事件消费流程,这里以为了方便理解只展示 ACTION_DOWN 事件的消费流程
    在这里插入图片描述
    ACTION_UP 会一模一样的再执行一遍,一次 ACTION_DOWN --> ACTION_UP 流程称为一次事件

在以上的流程中,我们只需要重点知道事件是怎么处理的(View)以及事件是怎么分发的就可以了(ViewGroup)

View 事件的分发 dispatchTouchEvent

一个事件,首先会进行一系列相关判断,我们这里只讲一下有关判断


// View 中的 dispatchTouchEvent 主要做的是事件交给哪个方法处理(onClick、onTouch)

public boolean dispatchTouchEvent(MotionEvent event) {
		ListenerInfo li = mListenerInfo;
        if (
        // mListenerInfo: 只要设置了类似于 onClickListener、onTouchListener等类似监听事件则都不为空
        li != null 
        // 是否设置了触摸监听事件
        && li.mOnTouchListener != null
        		// view 是否可点击
                && (mViewFlags & ENABLED_MASK) == ENABLED
                // 触摸监听是否返回的 true,也就是说事件是否被触摸时候消费了,这里也是 onTouch 方法的调用的地方
                && li.mOnTouchListener.onTouch(this, event)) {
            // 如果以上条件都符合,则标记为 true
            result = true;
            // 综上,以上判断条件的关键判断为设置 onTouchListener 监听后 onTouch 方法的返回结果
        }
		// onTouchEvent 的执行位置在这个判断中
		// onTouch 的返回结果 决定了 onTouchEvent 是否执行
		// 也就是说事件在 onTouch 中被消费了,就不会在 onTouchEvent 中再次消费了
		// 也说明了事件只能有一处消费,不仅仅是在不同 View 中,同一个 View 中也是
        if (!result && onTouchEvent(event)) {
            result = true;
        }
        // 实际的运行效果,onTouchListener 返回 true,onClickListener 不执行
        // 因为 onClick 方法在 onTouchEvent 中被调用
}

View 事件的处理(消费)onTouchEvent:

在 dispatchTouchEvent 中调用,不一定会被调用

    public boolean onTouchEvent(MotionEvent event) {
    	final int action = event.getAction();
    	case MotionEvent.ACTION_UP:
    		break;
		case MotionEvent.ACTION_DOWN:
            break;
		case MotionEvent.ACTION_CANCEL:
		    break;
		case MotionEvent.ACTION_MOVE:
		    break;
    }

ViewGroup

ViewGroup 事件的分发 dispatchTouchEvent

ViewGroup 中的 dispatchTouchEvent 主要做的是,事件分发给谁去处理(本身、子 View)

在执行过程中,主要有三个大的流程

  1. 判断是否拦截事件
  2. 将事件分发给子 View
  3. 处理事件

而 1 的结果决定 2 是否执行

// ViewGroup 的 dispatchTouchEvent 
// 如果事件被当前 View 拦截了,代码的执行
    	public boolean dispatchTouchEvent(MotionEvent ev) {
    		
    		// 第一个流程,判断是否拦截
    		final boolean intercepted;
            if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) {
                final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
                if (!disallowIntercept) {
                	// onInterceptTouchEvent 的调用的地方
                	// 主要代码,执行拦截方法,获取是否要拦截,此返回值决定了第二部分代码是否执行
                    intercepted = onInterceptTouchEvent(ev);
                    ev.setAction(action); // restore action in case it was changed
                } else {
                    intercepted = false;
                }
            } else {
                // There are no touch targets and this action is not an initial down
                // so this view group continues to intercept touches.
                intercepted = true;
            }
            
            // 第二个流程
            if (!canceled && !intercepted) {
            	if (actionMasked == MotionEvent.ACTION_DOWN
                        || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
                        || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
                    // ACTION_MOVE 时不执行
                }
            }
            
            // 第三个流程
    		if (mFirstTouchTarget == null) {
                // 自己本身去处理这个事件
                handled = dispatchTransformedTouchEvent(ev, canceled, null,
                        TouchTarget.ALL_POINTER_IDS);
                // 最终调用 super.dispatchTouchEvent() 这里的 super 指的是父类,而不是当前的父 ViewGroup
            } else {
            	
            }
    	}
    	
    	// ---------------------------------------------------------------------------
// 如果事件当前 View 不拦截,代码的执行
public boolean dispatchTouchEvent(MotionEvent ev) {
    		
    		// 第一个流程,判断是否拦截
    		final boolean intercepted;
            if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) {
                final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
                if (!disallowIntercept) {
                	// onInterceptTouchEvent 的调用的地方
                	// 主要代码,执行拦截方法,获取是否要拦截,此返回值决定了第二部分代码是否执行
                    intercepted = onInterceptTouchEvent(ev);
                    ev.setAction(action); // restore action in case it was changed
                } else {
                    intercepted = false;
                }
            } else {
                // There are no touch targets and this action is not an initial down
                // so this view group continues to intercept touches.
                intercepted = true;
            }
            
            // 第二个流程
            if (!canceled && !intercepted) {
                 if (actionMasked == MotionEvent.ACTION_DOWN
                        || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
                        || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
                    // ACTION_MOVE 时不执行
                }
            	...
            	
            	//
            	for (int i = childrenCount - 1; i >= 0; i--) {
            		final int childIndex = getAndVerifyPreorderedIndex(
                                    childrenCount, i, customOrder); 
                    final View child = getAndVerifyPreorderedView(
                                    preorderedList, children, childIndex);

					// 询问当前 View 是否消费,如果不消费则继续寻找下一个
					if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
					}
					mLastTouchDownX = ev.getX();
                    mLastTouchDownY = ev.getY();
                    newTouchTarget = addTouchTarget(child, idBitsToAssign);
                    alreadyDispatchedToNewTouchTarget = true;
            	}
            }
            
            // 第三个流程
    		if (mFirstTouchTarget == null) {
    		
            } else {
            	TouchTarget predecessor = null;
                TouchTarget target = mFirstTouchTarget;
                
                // 多指操作处理
                while (target != null) {
                    final TouchTarget next = target.next;
                    
                    // 
                    if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
                        handled = true;
                    } else {
                        final boolean cancelChild = resetCancelNextUpFlag(target.child)
                                || intercepted;
                        if (dispatchTransformedTouchEvent(ev, cancelChild,
                                target.child, target.pointerIdBits)) {
                            handled = true;
                        }
                        if (cancelChild) {
                            if (predecessor == null) {
                                mFirstTouchTarget = next;
                            } else {
                                predecessor.next = next;
                            }
                            target.recycle();
                            target = next;
                            continue;
                        }
                    }
                    predecessor = target;
                    target = next;
                }
            }
    	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值