ViewGroup和View事件分发机制(简单白话文)

事件分发机制的目的是:只让一个View拥有控制事件的权力,并找出这个View记录再将权力分发给它。

1.dispatchTouchEvent 用来进行事件分发.
如果事件能够传递给当前View,那么此方法一定会被调用。
返回结果受当前View的OnTouchEvent和child的disPatchTouchEvent控制。表示是否消耗
public boolean dispatchTouchEvent(MotionEvent ev);
单纯的返回boolean结果没有意义,其中的IntercepterTouchEvent,onTouchEvent都会在super.dispatchTouchEvent()中调用;


2.onInterceptTouchEvent 
会在dispatchTouchEvent中调用
用来判断是否需要拦截某个事件
在同一个事件序列中,此方法只会被调用一次
返回结果表示是否拦截当前事件
仅ViewGroup有此方法,View没有,只要传到View的dispatchTouchEvent事件,那么便会走OnTouchvent方法
public boolean interceptTouchEvent(MotionEvent ev);

3.onTochEvent
这个方法返回的true和false并不意味着让当前View使用这个方法,
只是说这个View类要获得事件的权力,让IntercepterTouthEvent(ViewGroup中,View没有这个方法)以后把事件权力都给我
public boolean onTochEvent(MotionEvent ev);

//这便是精髓
dispatchTouchEvent(){
    boolean result=false;
    if(intercepterTouch()){
        result = OnTouchEvent();
        return result;
    }else{
        result = children.dispatchTouchEvent();
        return result;
        }
}

***有些人总是自己用logd测试出child类的OnTouchEvent方法会比parent类的dispatchTouchEvent先打印,
   Log.d(TAG, "dispatchTouchEvent: "+super.dispatchTouchEvent(ev));
那是因为你打印之前先执行了super.dispatchTouchEvent(),
所以会调用上面这段精髓代码,而且intercepterTouch()默认返回false
    parent.dispatchTouchEvent()方法中会调用-->
    parent.intercepter()-->返回false 使得在dispatch()接着调用children.dispatchTouchEvent()
    如果children也是ViewGroup,那么会循环继续调用到他的children,一直到View的dispatch()
    而View没有Intercepter,所以直接调用OnTouchEvent,所以你看到了children的OnTouchEvent先打印
以上一段你会发现,一切都是在parent类的dispatchTouchEvent()内部执行的。


***那么现在再理一理,在不拦截(不返回true,在interceptTouchEvent()中),事件顺序:
    parent.dispatchTouchEvent()-->parent.intercepterTouch()返回false-->    
    child.dispatchTouchEvent()-->child.intercepterTouch()返回false-->    
                                …………………………
    当child为View时,child.dispatchTouchEvent()-->child.onTouchEvent()-->
    child.onTouchEvent()返回的boolean类型如果是false,那么parent类的dispatchTouchEvent方法会调用super.dispatchTouchEvent()(源码中有),
    
    <这个是自己分析的>也就是View中的方法,View中没有Intercepter,那么会直接调用onTouchEvent方法,这个也就是parent的OnTouchEvent()<这个是自己分析的/>,
    
    所以如果child类中onTouch返回为false,那么会一直往parent的onTouch中跑,直到某层返回true,此时不仅调用,并且**记录**
    同一个事件序列中便不会再次调用本层的IntercepterTouchEvent(),而是直接intercepter=true,
    此时拦截并执行本层的onTouch,现在就不会走child中的dis和tou了.直到下一个事件序列的down事件
    

    下面放源码: 关于 **记录**
            final boolean intercepted;
            // 当交由Child处理时 mFirstTouchTarget != null  
           //当不是down事件,并且不给child处理时,intercepted = true;  
           //就是说当强行拦截,上面说的记录便是指的这个 mFirstTouchTarget;赋值过程在后面addTouchTarget();
            if (actionMasked == MotionEvent.ACTION_DOWN
                    || mFirstTouchTarget != null) {
            //FLAG_DISALLOW_INTERCEPT 这个子类可以设置,用来要求不拦截,除了Down事件,大家肯定用过。
                final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
                if (!disallowIntercept) {
                    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;
            }


下面放源码: 关于  如果child类中onTouch返回为false,那么会一直往parent的onTouch中跑
     if (child == null) {
                //View的dis方法,没有Inter,会直接OnTouch
                handled = super.dispatchTouchEvent(event);
            } else {
                handled = child.dispatchTouchEvent(event);
            }
                
    其中的  handled = child.dispatchTouchEvent(event),如果返回true也就是说children要事件,
        那么会给mFirstTouchTarget赋值:  进行标记
         private TouchTarget addTouchTarget(@NonNull View child, int pointerIdBits) {
        final TouchTarget target = TouchTarget.obtain(child, pointerIdBits);
        target.next = mFirstTouchTarget;
        mFirstTouchTarget = target;
        return target;
         }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值