触摸事件分发

android触摸事件的分发和处理 这两天学习了下Android触摸事件。 记录下: 首先对事件的理解如下。 一个事件由down move up 三个动作组成,其中move动作可以有多个或者0个,但down 和up动作有且只有一个。这个三个动作中down是最先响应的,它是先驱,由它来决定move和up动作响应路线。 以event对象为主线,对事件分发和响应整个流程理解如下: (前提是在一个Activity,一个Linear 阅读详情

触摸事件

在这里插入图片描述

代码

根布局



public class RootLinearLayout extends LinearLayout {
    public RootLinearLayout(Context context) {
        super(context);
    }

    public RootLinearLayout(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.e("touch", "RootLinearLayout--->dispatchTouchEvent--->根--->分发事件开始***********************");
        boolean b = super.dispatchTouchEvent(ev);

        Log.e("touch", "根--->分发事件结束+" + b);
        return b;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e("touch", "RootLinearLayout--->onTouchEvent--->根--->处理事件开始***********************");
        boolean b = super.onTouchEvent(event);

        Log.e("touch", "根--->处理事件结束+" + b + event.getAction());
        return b;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.e("touch", "RootLinearLayout--->onInterceptTouchEvent--->根--->拦截事件开始***********************");
        boolean b = super.onInterceptTouchEvent(ev);
        Log.e("touch", "根--->拦截事件结束+" + b);

        return b;
    }
}

父布局


public class ParentLinearLayout extends LinearLayout{
    public ParentLinearLayout(Context context) {
        super(context);
    }

    public ParentLinearLayout(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }
    

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.e("touch","ParentLinearLayout--->dispatchTouchEvent--->父--->分发事件开始***********************");
        boolean b = super.dispatchTouchEvent(ev);
        Log.e("touch","父--->分发事件结束+"+ b);
        return b;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e("touch","ParentLinearLayout--->onTouchEvent--->父--->处理事件开始***********************");
        boolean b = super.onTouchEvent(event);
        Log.e("touch","父--->处理事件结束+"+ b+event.getAction());
        return b;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.e("touch","ParentLinearLayout--->onInterceptTouchEvent--->父--->拦截事件开始***********************");
        boolean b = super.onInterceptTouchEvent(ev);
        Log.e("touch","父--->拦截事件结束+"+ b);

        return b;
//        return true;
    }
}

子布局



public class ChildTextView extends AppCompatTextView {
    public ChildTextView(Context context) {
        super(context);
    }

    public ChildTextView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.e("touch", "ChildTextView--->dispatchTouchEvent--->子--->分发事件***********************");
        boolean b = super.dispatchTouchEvent(ev);
        Log.e("touch", "子--->分发事件+" + b);
        return b;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e("touch", "ChildTextView--->onTouchEvent--->子--->处理事件***********************");
        boolean b = super.onTouchEvent(event);
        Log.e("touch", "子--->处理事件+" + b + event.getAction());
        return b;
    }


}

好的log

考虑根+父两层关系

log1 全部返回false
RootLinearLayout--->dispatchTouchEvent--->根--->分发事件***********************
RootLinearLayout--->onInterceptTouchEvent--->根--->拦截事件***********************
根--->拦截事件+false
            ParentLinearLayout--->dispatchTouchEvent--->父--->分发事件***********************
            ParentLinearLayout--->onInterceptTouchEvent--->父--->拦截事件***********************
            父--->拦截事件+false
            ParentLinearLayout--->onTouchEvent--->父--->处理事件***********************
            父--->处理事件+false0
            父--->分发事件+false
RootLinearLayout--->onTouchEvent--->根--->处理事件***********************
根--->处理事件+false0
根--->分发事件+false
log2 只是根布局onInterceptTouchEvent返回true
RootLinearLayout--->dispatchTouchEvent--->根--->分发事件开始***********************
RootLinearLayout--->onInterceptTouchEvent--->根--->拦截事件开始***********************
根--->拦截事件结束+true
RootLinearLayout--->onTouchEvent--->根--->处理事件开始***********************
根--->处理事件结束+false0
根--->分发事件结束+false

log3 只是根布局dispatchTouchEvent返回true
处理Down事件
RootLinearLayout--->dispatchTouchEvent--->根--->分发事件开始***********************
RootLinearLayout--->onInterceptTouchEvent--->根--->拦截事件开始***********************
根--->拦截事件结束+false
        ParentLinearLayout--->dispatchTouchEvent--->父--->分发事件开始***********************
        ParentLinearLayout--->onInterceptTouchEvent--->父--->拦截事件开始***********************
        父--->拦截事件结束+false
        ParentLinearLayout--->onTouchEvent--->父--->处理事件开始***********************
        父--->处理事件结束+false0
        父--->分发事件结束+false
RootLinearLayout--->onTouchEvent--->根--->处理事件开始***********************
根--->处理事件结束+false0//0表示为Down事件
根--->分发事件结束+true


处理之后的move事件
RootLinearLayout--->dispatchTouchEvent--->根--->分发事件开始***********************
RootLinearLayout--->onTouchEvent--->根--->处理事件开始***********************
根--->处理事件结束+false2//2表示move事件
根--->分发事件结束+true

处理之后的up事件
RootLinearLayout--->dispatchTouchEvent--->根--->分发事件开始***********************
RootLinearLayout--->onTouchEvent--->根--->处理事件开始***********************
根--->处理事件结束+false1//1表示up事件
根--->分发事件结束+true
log4 只是根布局onTouchEvent返回true
处理Down事件
RootLinearLayout--->dispatchTouchEvent--->根--->分发事件开始***********************
RootLinearLayout--->onInterceptTouchEvent--->根--->拦截事件开始***********************
根--->拦截事件结束+false
        ParentLinearLayout--->dispatchTouchEvent--->父--->分发事件开始***********************
        ParentLinearLayout--->onInterceptTouchEvent--->父--->拦截事件开始***********************
        父--->拦截事件结束+false
        ParentLinearLayout--->onTouchEvent--->父--->处理事件***********************
        父--->处理事件结束+false0
        父--->分发事件结束+false
        RootLinearLayout--->onTouchEvent--->根--->处理事件开始***********************
根--->处理事件结束+true0//关键在这★★★★★,根布局onTouchEvent返回true,就会导致根布局dispatchTouchEvent返回true,从而使得以后的所有事件被根布局处理
根--->分发事件结束+true


处理move事件
RootLinearLayout--->dispatchTouchEvent--->根--->分发事件开始***********************
RootLinearLayout--->onTouchEvent--->根--->处理事件开始***********************
根--->处理事件结束+true2
根--->分发事件结束+true

处理up事件
RootLinearLayout--->dispatchTouchEvent--->根--->分发事件开始***********************
RootLinearLayout--->onTouchEvent--->根--->处理事件开始***********************
根--->处理事件结束+true2
根--->分发事件结束+true
RootLinearLayout--->dispatchTouchEvent--->根--->分发事件开始***********************
RootLinearLayout--->onTouchEvent--->根--->处理事件开始***********************
根--->处理事件结束+true1
根--->分发事件结束+true

分析1

一、对比log1和log2:

  1. 根布局onInterceptTouchEvent返回true,则父布局接收不到任何事件

二、对比log1和log3:

  1. 根布局dispatchTouchEvent返回false,根布局只接受到了Down事件,没有接收到之后的move、up事件
  2. 根布局dispatchTouchEvent返回true,根布局不仅仅接受到了Down事件,而且会接管之后的所有事件,之后的move、up事件都是由根布局处理的,其子布局不会在接收到任何事件
  3. 还可以看到一点,只要根布局在第一次Down事件时dispatchTouchEvent返回true,以后不会再去询问根布局的onInterceptTouchEvent方法,是由根布局自己直接处理触摸事件的
    在这里插入图片描述
  4. 是当前ViewGroup拦截后,就不会再次询问onInterceptTouchEvent方法,但是如果是其子View处理了事件,是会继续询问onInterceptTouchEvent的,下图解释了

在这里插入图片描述


三、对比log1和log4:
1.可以看出,根布局onTouchEvent返回true,就会导致根布局dispatchTouchEvent返回true,从而使得以后的所有事件被根布局处理

即:onTouchEvent(true)---->dispatchTouchEvent(true)---->处理以后的所有事件

log5 只是父布局dispatchTouchEvent返回true
//第一次down事件
RootLinearLayout--->dispatchTouchEvent--->根--->分发事件开始***********************
RootLinearLayout--->onInterceptTouchEvent--->根--->拦截事件开始***********************
根--->拦截事件结束+false
        ParentLinearLayout--->dispatchTouchEvent--->父--->分发事件开始***********************
        ParentLinearLayout--->onInterceptTouchEvent--->父--->拦截事件开始***********************
        父--->拦截事件结束+false
        ParentLinearLayout--->onTouchEvent--->父--->处理事件开始***********************
        父--->处理事件结束+false0
        父--->分发事件结束+true
根--->分发事件结束+true

//第二次move事件
RootLinearLayout--->dispatchTouchEvent--->根--->分发事件开始***********************
RootLinearLayout--->onInterceptTouchEvent--->根--->拦截事件开始***********************
根--->拦截事件结束+false
        ParentLinearLayout--->dispatchTouchEvent--->父--->分发事件开始***********************
        ParentLinearLayout--->onTouchEvent--->父--->处理事件开始***********************
        父--->处理事件结束+false2
        父--->分发事件结束+true
根--->分发事件结束+true

//第三次move事件
RootLinearLayout--->dispatchTouchEvent--->根--->分发事件开始***********************
RootLinearLayout--->onInterceptTouchEvent--->根--->拦截事件开始***********************
根--->拦截事件结束+false
        ParentLinearLayout--->dispatchTouchEvent--->父--->分发事件开始***********************
        ParentLinearLayout--->onTouchEvent--->父--->处理事件开始***********************
        父--->处理事件结束+false2
        父--->分发事件结束+true
根--->分发事件结束+true


//第四次up事件
RootLinearLayout--->dispatchTouchEvent--->根--->分发事件开始***********************
RootLinearLayout--->onInterceptTouchEvent--->根--->拦截事件开始***********************
根--->拦截事件结束+false
        ParentLinearLayout--->dispatchTouchEvent--->父--->分发事件开始***********************
        ParentLinearLayout--->onTouchEvent--->父--->处理事件开始***********************
        父--->处理事件结束+false1
        父--->分发事件结束+true
根--->分发事件结束+true
分析2

对比log1和log5
1.只是父布局dispatchTouchEvent返回true,发现根布局的dispatchTouchEvent也返回了true,说明一个ViewGroup的dispatchTouchEvent返回值,不但与他自身的onTouchEvent返回值有关系,还与他的子View的dispatchTouchEvent有关系
2.子dispatchTouchEvent(true)—>父dispatchTouchEvent(true
3.自身onTouchEvent(true)—>自身onTouchEvent(true)
4.如果下级的dispatchTouchEvent返回了true,以后的事件都有下级处理(当然有多个下级的情况,最下级返回true,他的上级都会返回true,那么以后的事件交给最下级的那个返回true的View处理)

在这里插入图片描述

在这里插入图片描述

考虑根+父+子三层关系

log1 全部返回false
RootLinearLayout--->dispatchTouchEvent--->根--->分发事件***********************
RootLinearLayout--->onInterceptTouchEvent--->根--->拦截事件***********************
根--->拦截事件+false
        ParentLinearLayout--->dispatchTouchEvent--->父--->分发事件***********************
        ParentLinearLayout--->onInterceptTouchEvent--->父--->拦截事件***********************
        父--->拦截事件+false
                ChildTextView--->dispatchTouchEvent--->子--->分发事件***********************
                ChildTextView--->onTouchEvent--->子--->处理事件***********************
                子--->处理事件+false0
                子--->分发事件+false
        ParentLinearLayout--->onTouchEvent--->父--->处理事件***********************
        父--->处理事件+false0
        父--->分发事件+false
RootLinearLayout--->onTouchEvent--->根--->处理事件***********************
根--->处理事件+false0
根--->分发事件+false

log2 只是子View的onTouchEvent返回true

//down
RootLinearLayout--->dispatchTouchEvent--->根--->分发事件开始***********************
RootLinearLayout--->onInterceptTouchEvent--->根--->拦截事件开始***********************
根--->拦截事件结束+false
        ParentLinearLayout--->dispatchTouchEvent--->父--->分发事件开始***********************
        ParentLinearLayout--->onInterceptTouchEvent--->父--->拦截事件开始***********************
        父--->拦截事件结束+false
                ChildTextView--->dispatchTouchEvent--->子--->分发事件开始***********************
                ChildTextView--->onTouchEvent--->子--->处理事件开始***********************
                子--->处理事件结束+true0
                子--->分发事件结束+true
        父--->分发事件结束+true
根--->分发事件结束+true


//move
RootLinearLayout--->dispatchTouchEvent--->根--->分发事件开始***********************
RootLinearLayout--->onInterceptTouchEvent--->根--->拦截事件开始***********************
根--->拦截事件结束+false
        ParentLinearLayout--->dispatchTouchEvent--->父--->分发事件开始***********************
        ParentLinearLayout--->onInterceptTouchEvent--->父--->拦截事件开始***********************
        父--->拦截事件结束+false
                ChildTextView--->dispatchTouchEvent--->子--->分发事件开始***********************
                ChildTextView--->onTouchEvent--->子--->处理事件开始***********************
                子--->处理事件结束+true2
                子--->分发事件结束+true
        父--->分发事件结束+true
根--->分发事件结束+true


//move
RootLinearLayout--->dispatchTouchEvent--->根--->分发事件开始***********************
RootLinearLayout--->onInterceptTouchEvent--->根--->拦截事件开始***********************
根--->拦截事件结束+false
        ParentLinearLayout--->dispatchTouchEvent--->父--->分发事件开始***********************
        ParentLinearLayout--->onInterceptTouchEvent--->父--->拦截事件开始***********************
        父--->拦截事件结束+false
                ChildTextView--->dispatchTouchEvent--->子--->分发事件开始***********************
                ChildTextView--->onTouchEvent--->子--->处理事件开始***********************
                子--->处理事件结束+true2
                子--->分发事件结束+true
        父--->分发事件结束+true
根--->分发事件结束+true


//up
RootLinearLayout--->dispatchTouchEvent--->根--->分发事件开始***********************
RootLinearLayout--->onInterceptTouchEvent--->根--->拦截事件开始***********************
根--->拦截事件结束+false
        ParentLinearLayout--->dispatchTouchEvent--->父--->分发事件开始***********************
        ParentLinearLayout--->onInterceptTouchEvent--->父--->拦截事件开始***********************
        父--->拦截事件结束+false
                ChildTextView--->dispatchTouchEvent--->子--->分发事件开始***********************
                ChildTextView--->onTouchEvent--->子--->处理事件开始***********************
                子--->处理事件结束+true1
                子--->分发事件结束+true
        父--->分发事件结束+true
根--->分发事件结束+true

####分析

  1. 如果子View的onTouchEvent返回true,导致子View的dispatchTouchEvent返回true,那么不会再次调用上层ViewGroup的onTouchEvent,而是直接调用其上层ViewGroup的dispatchTouchEvent,并且返回true
  2. 以后所有事件都交由子View处理
log3 只是父ViewGroup的dispatchTouchEvent返回true
//down
RootLinearLayout--->dispatchTouchEvent--->根--->分发事件开始***********************
RootLinearLayout--->onInterceptTouchEvent--->根--->拦截事件开始***********************
根--->拦截事件结束+false
        ParentLinearLayout--->dispatchTouchEvent--->父--->分发事件开始***********************
        ParentLinearLayout--->onInterceptTouchEvent--->父--->拦截事件开始***********************
        父--->拦截事件结束+false
                ChildTextView--->dispatchTouchEvent--->子--->分发事件开始***********************
                ChildTextView--->onTouchEvent--->子--->处理事件开始***********************
                子--->处理事件结束+false0
                子--->分发事件结束+false
        ParentLinearLayout--->onTouchEvent--->父--->处理事件开始***********************
        父--->处理事件结束+false0
        父--->分发事件结束+true
根--->分发事件结束+true



//move
RootLinearLayout--->dispatchTouchEvent--->根--->分发事件开始***********************
RootLinearLayout--->onInterceptTouchEvent--->根--->拦截事件开始***********************
根--->拦截事件结束+false
        ParentLinearLayout--->dispatchTouchEvent--->父--->分发事件开始***********************
        ParentLinearLayout--->onTouchEvent--->父--->处理事件开始***********************
        父--->处理事件结束+false2
        父--->分发事件结束+true
根--->分发事件结束+true



//up
RootLinearLayout--->dispatchTouchEvent--->根--->分发事件开始***********************
RootLinearLayout--->onInterceptTouchEvent--->根--->拦截事件开始***********************
根--->拦截事件结束+false
ParentLinearLayout--->dispatchTouchEvent--->父--->分发事件开始***********************
ParentLinearLayout--->onTouchEvent--->父--->处理事件开始***********************
父--->处理事件结束+false1
父--->分发事件结束+true
根--->分发事件结束+true
分析
  1. 只是父ViewGroup的dispatchTouchEvent返回true,这里虽然onInterceptTouchEvent依然返回false,以后的事件都交给了父ViewGroup处理了,而且以后不再询问自身的onInterceptTouchEvent方法了
  2. 可见只要dispatchTouchEvent返回true就表明,以后都是他 来处理事件,
  3. dispatchTouchEvent是一个重要标志,而不是onTouchEvent,只不过默认情况下onTouchEvent返回了true,会导致dispatchTouchEvent返回true,所以看起来onTouchEvent是决定了以后的事件由他处理的标志,但在本例中,onTouchEvent返回false,但我们强行让dispatchTouchEvent返回true。
log4 只是子View的dispatchTouchEvent返回true

log不贴了,直接说结果:
子View接着处理以后的所有事件
所以说最下级的那个dispatchTouchEvent返回ture的view处理以后的事件

总结

public class WeiDaiMa {

    WeiDaiMa child;


    /**
     * ViewGroup的dispatchTouchEvent
     * 用来分发触摸事件
     * 虽然ViewGroup继承自View,但是他重写了dispatchTouchEvent方法,所以这里区分一下
     *
     * @param ev
     * @return
     */

    public boolean dispatchTouchEvent4ViewGroup(MotionEvent ev) {
        Boolean consume = false;

        if (当前ViewGroup要不要拦截事件(ev)) {//如果本ViewGroup拦截事件,那么调用本ViewGroup的onTouchEvent
            consume = onTouchEvent(ev);
        } else {//否则,调用子View的dispatchTouchEvent,子ViewGroup的dispatchTouchEvent逻辑是一样的
            consume = child.dispatchTouchEvent4ViewGroup(ev);////如果child为viewgroup
//            consume = child.dispatchTouchEvent4View(ev);//如果child为view
        }

        return consume;//返回true,表示事件被消耗了,
        // 如果是最里层级的view或ViewGroup的dispatchTouchEvent返回true,表示由本ViewGroup来处理以后的事件

    }

    private boolean 当前ViewGroup要不要拦截事件(MotionEvent ev) {
        boolean intercepted;
        if (ev.getAction() == MotionEvent.ACTION_DOWN
                || 本ViewGroup有子View_且_本ViewGroup不拦截事件_交给了子View处理_且_子View的dispatchTouchEvent返回true_即子View处理了事件) {
            if (子View请求拦截_requestDisallowInterceptTouchEvent(false)) {
                //询问本ViewGroup的onInterceptTouchEvent,要不要拦截事件
                intercepted = onInterceptTouchEvent(ev);
            } else {
                intercepted = false;//如果子View请求不拦截,那么默认返回false
            }
        } else {
            //当这个事件不是ACTION_DOWN,并且当前的ViewGroup也没有子ViewGroup(view)可以处理事件,那么就由本ViewGroup拦截这个事件
            intercepted = true;
        }
        return intercepted;
    }

    /**
     * ViewGroup 和 View 的onTouchEvent是一样的 都是view的,
     * 因为ViewGroup是view的子类,且ViewGroup没有重写view的onTouchEvent
     * 用来处理触摸事件
     *
     * @param ev
     * @return
     */
    private Boolean onTouchEvent(MotionEvent ev) {

//            如果控件可点击返回true,否则返回false
        if (isClickable || isLongClickable) {
//            onTouchListener.onTouch--优先于-》onTouchEvent-优先于--》onClick
//            执行click接口
            return true;
        } else {
            return false;
        }
    }

    /**
     * ViewGroup特有的方法
     * 用来判断是否拦截触摸事件
     * 这个方法不一定每次都要都要,他是有条件的 ,见 《当前ViewGroup要不要拦截事件》
     *
     * @param ev
     * @return
     */
    private boolean onInterceptTouchEvent(MotionEvent ev) {

//默认返回false,
// 可以在这里重写,定义在down时候,返回false不拦截
// down up事件返回true拦截   配合子view的requestDisallowIntenceot方法
//        其实requestDisallowInterceptTouchEvent(false)):子view请求拦截,让父view去询问下自己的onInterceptTouchEvent方法,看看要不要拦截
//        如果requestDisallowInterceptTouchEvent(true):子view请求不要拦截,那就直接返回false,不去拦截
        return false;
    }


//    ===================================================================================================

    /**
     * View的dispatchTouchEvent
     * 用来分发触摸事件
     *
     * @param ev
     * @return
     */

    public boolean dispatchTouchEvent4View(MotionEvent ev) {
//        如果控件可用&&设置了mOnTouchListener,&&onTouch方法返回true,该方法直接返回true,不去调用onTouchEvent方法
        if (mOnTouchListener != null && enable && mOnTouchListener.onTouch(ev)) {
            return true;
        } else {
            return onTouchEvent(ev);
        }


    }


}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

总结

精华1

  1. dispatchTouchEvent:

    所有的事件分发,都是从父ViewGroup的dispatchTouchEvent开始的

      public boolean dispatchTouchEvent(MotionEvent ev) {
            Boolean consume = false;
            if (当前ViewGroup要不要拦截事件(ev)) {
            //如果本ViewGroup拦截事件,那么调用本ViewGroup的onTouchEvent
                consume = onTouchEvent(ev);
            } else {
            //否则,调用子View的dispatchTouchEvent,子ViewGroup的dispatchTouchEvent逻辑是一样的
                consume = child.dispatchTouchEvent(ev);
            return consume;//返回true,表示事件被消耗了,
            // 如果是最里层级的view或ViewGroup的dispatchTouchEvent返回true,表示由本ViewGroup来处理以后的事件
    
        }
    
  2. onInterceptTouchEvent:

    在dispatchTouchEvent内部调用,准确地说是在《当前ViewGroup要不要拦截事件(ev)》这个方法里调用。
    (《…》这是我自己抽取的一个方法,其实也是在dispatchTouchEvent内部调用)

    注意:onInterceptTouchEvent不一定每次都调用,仅仅当down事件来临时,或者其子view已经成功处理了触摸事件时,才会调用,换句话说,如果子view如果没有处理事件,那么,就不会询问onInterceptTouchEvent方法了,直接返回true,自己处理

    《当前ViewGroup要不要拦截事件(ev)》—这个方法的具体逻辑是

    
    
    
     boolean intercepted;
       if(DOWN事件 |或| 其子view消费了触摸事件) {
            if (子View请求拦截) {//即:requestDisallowInterceptTouchEvent(false)
                //询问本ViewGroup的onInterceptTouchEvent,要不要拦截事件
                intercepted = onInterceptTouchEvent(ev);
            } else {
                //如果子View请求不拦截,那么直接返回false
                intercepted = false; 
                    }
        } else {
            //当这个事件不是ACTION_DOWN,并且当前的ViewGroup也没有子ViewGroup(view)可以处理事件,那么就由本ViewGroup拦截这个事件
            intercepted = true;
        }
        return intercepted;
    
  3. 说下requestDisallowInterceptTouchEvent(boolean)

    注意是在子view里通过,getParent().requestDisallowInterceptTouchEvent(boolean)来使用

    - requestDisallowInterceptTouchEvent(false):
    子view请求拦截,让父view去询问下自己的onInterceptTouchEvent方法,看看要不要拦截
    
    - requestDisallowInterceptTouchEvent(true):
    子view请求不要拦截,那就直接返回false,不去拦截
       
    
  4. onTouchEvent

    也是在dispatchTouchEvent内部调用的,但是他是当ViewGroup要处理事件时候,通过调用该ViewGroup的父类View.dispatchTouchEvent时,调用了onTouchEvent,也就是说,严格来讲,onTouchEvent是View.dispatchTouchEvent调用的

       /**
        * ViewGroup 和 View 的onTouchEvent是一样的 都是view的,
        * 因为ViewGroup是view的子类,且ViewGroup没有重写view的onTouchEvent
        * 用来处理触摸事件
        *
        * @param ev
        * @return
        */
       private Boolean onTouchEvent(MotionEvent ev) {
   
             // 如果控件可点击返回true,否则返回false
           if (isClickable || isLongClickable) {
            //            onTouchListener.onTouch--优先于-》onTouchEvent-优先于--》onClick
            //            执行click接口
               return true;
           } else {
               return false;
           }
       }
       
  1. 说一下View的dispatchTouchEvent

    /**
         * View的dispatchTouchEvent
         * 用来分发触摸事件
         *
         * @param ev
         * @return
         */
    
        public boolean dispatchTouchEvent4View(MotionEvent ev) {
    //        如果控件可用&&设置了mOnTouchListener,&&onTouch方法返回true,该方法直接返回true,不去调用onTouchEvent方法
            if (mOnTouchListener != null && enable && mOnTouchListener.onTouch(ev)) {
                return true;
            } else {
                return onTouchEvent(ev);
            }
    
    
        }
    

    可直接看
    Android事件分发机制 详解攻略,您值得拥有

Android触摸事件分发详解 在Android中,触摸事件的分发是通过ViewGroup的dispatchTouchEvent()方法和View的dispatchTouchEvent()方法以及onTouchEvent()方法来实现的。在onTouchEvent()方法中根据事件的类型执行相应的操作,并返回true表示消费事件。触摸事件是Android开发中常见的交互方式之一。在Android中,触摸事件的分发是通过ViewGroup的dispatchTouchEvent()方法以及View的onTouchEvent()方法来实现的。 阅读详情

相关推荐

Zotero内存占用与存储优化:从根源解决卡顿与空间不足

文献管理软件在学术工作中扮演着重要角色,其核心原理是通过数据库管理元数据与附件文件,实现文献的快速检索与组织。然而,随着文献库规模增长,软件的资源管理机制可能面临挑战,尤其是内存占用与存储空间优化问题。从技术价值看,高效的附件管理策略不仅能提升软件响应速度,还能确保数据安全与可移植性。在实际应用场景中,研究者常遇到软件卡顿、存储目录膨胀等痛点,这通常与附件存储模式、缓存机制及数据库维护有关。本文聚焦于Zotero这一主流工具,针对其内存占用高、文件无法删除等常见问题,提供了外置存储、链接附件、数据库维护等系

weixin_34209060的博客 474

事件分发机制

android是事件分分发机制

yu_ren_的博客 2917

经典损失函数——均方误差(MSE)和交叉熵误差(CEE)的python实现

损失函数(loss function)用来表示当前的神经网络对训练数据不拟合的程度。这个损失函数有很多,但是一般使用均方误差和交叉熵误差等。 1.均方误差(mean squared error) 先来看一下表达式: 用于将的求导结果变成,是神经网络的输出,是训练数据的标签值,k表示数据的维度。 用python实现: def MS...

Answer3664的博客 1万+

移动端Touch (触摸)事件

一:常见的触摸事件:touchstart、touchmove和touchend。 touchstart事件:当手指触摸屏幕时候触发,即使已经有一个手指放在屏幕上也会触发。 touchmove事件:当手指在屏幕上滑动的时候连续地触发。在这个事件发生期间,调用 preventDefault()事件可以阻止滚动。 touchend事件:当手指从屏幕上离开的时候触发。 二:触摸事件...

qq_51379218的博客 8459

基于Dify构建银行智能客服:从意图识别到多RAG架构的实战解析

本文深入解析了如何利用Dify平台构建银行智能客服系统。从传统客服痛点出发,详细阐述了基于意图识别精准分类用户需求,并通过多RAG架构解决知识混淆问题,实现高效、准确的业务响应。文章重点介绍了结合工具调用实现业务流程自动化,并强调了数据本地化部署、内容安全过滤等银行级安全合规实践,为金融行业AI应用提供了实战指南。

yog99的博客 926

Win10 LTSC 2021 CPU占用率飙升?KB5017308补丁修复全攻略

本文针对Windows 10 LTSC 2021系统中因wsappx进程导致的CPU占用率异常飙升问题,提供了详细的解决方案。核心在于安装微软官方发布的KB5017308补丁,该补丁能从根本上修复系统组件缺陷,使CPU占用恢复正常。文章详解了补丁的下载、安装步骤、注意事项及安装后的验证方法,是解决此问题的权威指南。

python9snake的博客 1280

Android事件分发机制详解:史上最全面、最易懂

点击事件由哪个对象发出,经过哪些对象,最终达到哪个对象并最终得到处理。这里的对象是指Activity、ViewGroup、View事件分发过程由dispatchTouchEvent() 、onInterceptTouchEvent()和onTouchEvent()三个方法协助完成经过上述3个问题,相信大家已经对Android的事件分发有了感性的认知,接下来,我将详细介绍Android事件分发机制。

w1142203475的博客 1万+

Claude Code 100个真实案例 - 用AI搭建LangChain多工具Agent(自主搜索+查询)

本案例展示如何使用 Claude Code 搭建一个 LangChain 多工具 Agent 系统。Agent 能够自主决定调用搜索引擎、数据库查询、天气查询、计算器等工具,像人类助手一样拆解问题并逐步解决。

yueyeguzhuo的专栏 560

触摸事件(touchstart、touchmove和touchend)

触摸事件(touch)会在用户手指放在屏幕上面的时候、在屏幕上滑动的时候或者是从屏幕上移开的时候出发。下面具体说明:   touchstart事件:当手指触摸屏幕时候触发,即使已经有一个手指放在屏幕上也会触发。   touchmove事件:当手指在屏幕上滑动的时候连续地触发。   touchend事件:当手指从屏幕上离开的时候触发。 除了常见的DOM属性,触摸事件还包含下面三个用于跟踪触摸的属性。也就是存在于事件的默认参数event中。   touches:表示当前跟踪的触摸操作的touch对象的数组。

weixin_42349568的博客 2万+

面向边缘计算的YOLOv12模型剪枝-蒸馏联合优化实战教程**

这套剪枝-蒸馏联合方案的优势在于其系统性和可靠性。它不是单一的技巧,而是一套完整的工程流程,确保了从研发到部署的无缝衔接。

FJN110的博客 160

ETAS工具导入Com Arxml修改步骤

通讯协议栈开发一般通过导入DBC实现,ETAS工具本身导入DBC也是生成arxml后执行cfggen,本文介绍直接导入客户提供的arxml文件,实现通讯协议栈的生成。通过Arxml导入相比于DBC来说,少了从DBC转为arxml的过程。而且arxml中能提供的信息也会更多。如果是DBC的话,很多信息(如PNC的映射,CANTP的配置等)都需要额外配置。不过还有连DBC都无法提供的,那就更麻烦了~

赞的博客 1543

Android touch事件分发机制★

首先先从源码的角度分析View的事件分发。 从一个简单的例子入手。比如说你当前有一个非常简单的项目,只有一个Activity,并且Activity中只有一个按钮。如果想要给这个按钮注册一个点击事件,只需要调用: button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Log.d(“TAG”, “onClick execute”); } }); 这样在onClick方法里面写实现,就可以

zenmela2011的专栏 2981

YOLO11 改进系列 | 引入2023年 MLCA 的 C3k2_MLCA 模块,近零参数开销的本地-全局通道注意力,适合检测与分割特征增强

本文提出将MLCA(混合局部通道注意力)模块嵌入YOLOv11的C3k2框架中,形成C3k2_MLCA改进结构。该模块通过5×5局部池化和1×1全局池化双路融合,结合ECA式Conv1d生成通道注意力,在几乎不增加参数量的前提下(仅增加66个参数),实现了局部空间信息与全局通道统计的联合建模。相比传统SE和ECA注意力,MLCA保留了空间分布信息,更适合实例分割等需要精细定位的任务。实验表明改进后模型参数量仅增加0.002%,计算量基本不变,是一种高效的注意力增强方案。

qq_44224801的博客 93

深入了解触摸事件的分发

1. 触摸动作及事件序列 (1)触摸事件的动作     触摸动作一共有三种:ACTION_DOWN、ACTION_MOVE、ACTION_UP。当用户手指接触屏幕时,便产生一个动作为ACTION_DOWN的触摸事件,此时若用户的手指立即离开屏幕,会产生一个动作为ACTION_UP的触摸事件;若用户手指接触屏幕后继续滑动,当滑动距离超过

Open Mind 644

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

安卓触摸事件分发机制分析

🎯 一句话总结:触摸事件(TouchEvent)会从Activity层开始,按从外到内的方式传递给每一个 ViewGroup/View,直到某个 View消费(consume)它,事件传递就会停止。📌 事件分发三个关键方法方法名所在类作用说明所有 View/ViewGroup事件分发入口,决定是否继续向下传递仅 ViewGroup是否拦截事件,阻止传递给子 View所有 View/ViewGroup事件的最终处理者(消费者)DecorView是一个应用窗口的根容器,它本质上是一个。

WriteBug001的博客 972

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

android触摸事件分发,Android 触摸事件分发ViewGroup&View

做笔记用,方便以后糊涂了,过来看看:贴代码的话就太多了,但是不贴又怕以后看不明白:子Viewimport android.content.Context;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.widget.Button;impor...

weixin_30861557的博客 112

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

触摸事件分发机制

触摸事件分发这是我之前写的一篇事件分发的博客,这篇文章是在看了《Android开发艺术探索》后写的,书中已经给出了【外部拦截法】和【内部拦截法】的模板代码,我们可以直接拿来使用即可,书中也给出了看源码后的重要结论,博客里我写了个demo,以打印log的方式验证了一遍,帮助理解了一遍事件分发的流程。更加详细内容可参考触摸事件分发。 本篇博客贴出【外部拦截法】和【内部拦截法】代码,供大家上手使用,然后...

Android_Study_OK的博客 597

android 触摸事件的分发,Android触摸事件分发

Android系统中 ViewGroup的子类都具有//用来分发TouchEventpublic boolean dispatchTouchEvent(MotionEvent ev)//用来拦截TouchEventpublic boolean onInterceptTouchEvent(MotionEvent ev)//用来处理TouchEventpublic boolean onTouchEve...

weixin_39787606的博客 185

Android-触摸事件分发

一、什么是触摸事件分发,分发的是什么? 触摸事件分发,顾名思义就是将触摸事件(MotionEvent)进行传递的过程。 MotionEvent也就是触摸事件,主要分为几种类型: 类型 介绍 MotionEvent.ACTION_DOWN 按下:一个已开始按下的手势,动作包含初始开始位置。 MotionEvent.ACTION_MOVE 移动:在DOWN和UP之间,包含最近的点以及自上次下移或移动事件以来的任何中间点。 产生多个move事件 MotionEvent. ACTION_

Jay_zjc的博客 601

触摸事件分发流程详解(三):触摸事件分发

Activity中的dispatchTouchEvent: 一、如果在自定义的Activity中复写dispatchTouchEvent方法,除非返回super.dispatchTouchEvent(),否则都将直接拦截view的事件分发。因为事件分发是在Activity的dispatchTouchEvent()方法中进行的,如下: dispatchTouchEvent public boolean dispatchTouchEvent(MotionEvent ev) { 1、接受到触摸事件的时候,调用这个

massonJ的博客 888

View 触摸事件分发例子

点击事件的触发流程好比去小区送快递,还不知道是谁的快递。 例子对照: 楼(ViewGroup)、进楼(ViewGroup.dispatchTouchEvent)、楼下门岗拦截(ViewGroup.onInterceptTouchEvent)、 住户房间(View)、进住户房间(View.dispatchTouchEvent)、询问用户收不收快递(View.onTouchEvent)、询问大楼管理...

qq_34224268的博客 1390

Android触摸事件分发机制详解

触摸事件分发机制一直以来都是Android中比较重要的一大块,自定义view,各种复杂的自定义手势交互都与触摸事件分发机制关系密切,想要做好这些,就要对触摸事件了解透彻,并且需要不断的去实践来加深印象,否则在自己去实现的时候就会茫然不知所措,同时这个知识点也是面试必问的经典题目,所以说掌握它是必须的,今天就来详细分析一下整个触摸事件的分发流程和相关知识。(本文理论知识较多,比较枯燥,需要极大耐心观看~)

Water的博客 4987

Android触摸事件分发机制精要

对于View感兴趣的事件,同时不想事件被ViewGroup拦截,则在View里调用mParent.requestDisallowInterceptTouchEvent(true)方法。如果View在onTouchEvent里返回false则表示对事件不感兴趣,从而View不会收到后续的MOVE和UP事件。如果View在onTouchEvent里返回true则表示对事件感兴趣,从而View可以收到后续的MOVE和UP事件;Activity在触摸机制中的作用:分发事件、处理View不感兴趣的事件。

weixin_55134590的博客 963

Android触摸事件分发

前言 在自定义ViewGroup中,有时候需要实现触摸事件拦截,比如ListView下拉刷新就是典型的触摸事件拦截的例子。触摸事件拦截就是在触摸事件被parent view拦截,而不会分发给其child,即使触摸发生在该child身上。被拦截的事件会转到parent view的onTouchEvent方法中进行处理。但是这个交互过程还是挺复杂的,有多种情况,今天我们就来分析一下吧。这篇分析文章已

细心程度决定你的成败 4314

触摸事件分发机制总结

从手指触摸到设备屏幕,直至手指离开设备屏幕,这个过程会不断的产生触摸事件,Framework称之为MotionEvent。 分发机制这是用于解决View的嵌套、重叠所产生的触摸事件应该由哪个view来响应的问题;比如: 点击上图中的button,这个点击的事件到底是应该由button响应呢,还是framelayout来响应呢。分发机制就是解决这样的问题的。负责事件分发的方法是dis

fyplant12的博客 1189
上一篇: Bintray上传Module到JCenter详细步骤(多图解释,不能再详细了)
下一篇: Git学习笔记
Android_Study_OK
博客等级 码龄11年 91粉丝 128原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值