美文网首页
view的事件分发

view的事件分发

作者: me_biubiu | 来源:发表于2020-05-21 11:00 被阅读0次

    https://www.cnblogs.com/chengxuyinli/p/9979826.html
    上面一篇文章重要的是伪代码部分

    这篇文章 viewgroup有段伪代码有些问题 更改如下

    // ViewGroup中该方法的核心部分伪代码
    public boolean dispatchTouchEvent(MotionEvent ev) {
            if (!onInterceptTouchEvent(ev)) {
                boolean handled = child.dispatchTouchEvent(ev);
                //不拦截,则传给子View进行分发处理
                if (!handled) {
                    return onTouchEvent(ev);
                } else {
                    return true;
                }
                //不拦截,则传给子View进行分发处理
            } else {
                return onTouchEvent(ev);    //拦截事件,交由自身对象的onTouchEvent方法处理
            }
        }
    

    "为什么子view 没有处理action_down的时候 后续都收不到触摸事件了" 以下一段也是伪代码,先看代码下方解释。

    // mFirstTouchTarget 可以理解为存储可以处理Touch事件的子View(不包括自身)的数据结构
    private TouchTarget mFirstTouchTarget;
    
    public boolean dispatchTouchEvent(MotionEvent ev) {
        // 是否中断
        final boolean intercepted;
        // 仅在ACTION_DOWN 和 已确定处理的子View时 调用,一旦onInterceptTouchEvent返回true,
        //则后续将不会在被调用和接收事件。后面会讲返回true后,mFirstTouchTarget会被为null;
        //1
        if (actionMasked == MotionEvent.ACTION_DOWN
                        || mFirstTouchTarget != null) {
                    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;
                }
        
        // 如果不被拦截,在ACTION_DOWN事件处理中遍历所有的子View,找寻可以处理Touch事件的目标子View
        // 然后封装到mFirstTouchTarget,如果子View的dispatchTouchEvent返回true,则认为是目标子View;
        //2
        if(!intercepted){
            if (action == MotionEvent.ACTION_DOWN) {
            //循环遍历直到找到愿意处理这个down事件的孩子
            for(View child:childs){
                if(child.dispatchTouchEvent(MotionEvent ev)){
                    mFirstTouchTarget = addTouchTarget(child);
                    break;
                }
            }
                
        
        }
        boolean handled;
        // 如果mFirstTouchTarget == null,调用自身onTouchEvent()
        //3
        if(mFirstTouchTarget == null){
            handled=onTouchEvent(ev);
        }else{
            // 应上面的逻辑,如果ACTION_MOVE传递过程中被拦截,则将mFirstTouchTarget置为null,并传递一个cancel事件,
            // 告诉目标子View当前动作被取消了,后续事件将不会再次被传递;
            //4
            if (intercepted){
                ev.action=MotionEvent.ACTION_CANCEL;
                handled=mFirstTouchTarget.child.dispatchTouchEvent(ev);
                mFirstTouchTarget=null;
            }else {
            //5
                // 调用目标子view的dispatchTouchEvent,这也是为什么,上面结论所述的,dispatchTouchEvent/onTouchEvent 
                // 在ACTION_DOWN事件返回true,不管子View返回什么值,都能收到后续事件,会出现所谓控制“失效”的现象。
                handled=mFirstTouchTarget.child.dispatchTouchEvent(ev);
            }
        }
        retrun handled;
    }
    

    不用看那么多细节 想那么多情况 主要考虑 "为什么子view 没有处理action_down的时候 后续都收不到触摸事件了"

    一 对于onInterceptTouchEvent方法走了默认逻辑的情况
    第一次是action_down :走到1处, if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null)判断走的是true逻辑,viewgroup的onInterceptTouchEvent默认reture false,所以intercepted=false,在2处就会遍历调用childs的dispatchTouchEvent,找有没有孩子愿意处理这个事件,

    a.(down如果有孩子处理,dispatchTouchEvent会返回true,mFirstTouchTarget.child就赋值为这个孩子的指针。那么3处就不会调用onTouchEvent了。然后4,5先不看。下一个event来,,viewgroup的onInterceptTouchEvent默认reture false,此时就没有2处遍历找能处理该事件的孩子的过程了(只在down的时候找,下次直接就交给down找到的孩子处理即mFirstTouchTarget.child)在3处判断mFirstTouchTarget此时不为空,intercepted=false,就走了5处的mFirstTouchTarget.child.dispatchTouchEvent(ev)。)

    b.(down如果没有孩子处理,mFirstTouchTarget=null,3处就走了这一层的onTouchEvent了,下个事件来了,1处也不拦截了(没必要了 孩子也不处理),3那直接走这一层的onTouchEvent了)。

    二,自己重写onInterceptTouchEvent方法的时候
    down事件的时候就拦截了,那么后面的事件子view都收不到了

    不是所有的View都有机会响应事件的 在Viewgroup的dispatchTouchEvent方法会倒序的遍历所有的childview 调用他们的方法区查看触摸点是不是在childview的触区内,是的话才传。

    相关文章

      网友评论

          本文标题:view的事件分发

          本文链接:https://www.haomeiwen.com/subject/exczohtx.html