dispatchTouchEvent事件分发浅析(四)Intercept拦截

上一篇,我们大体理解了分发的过程,并且简单做了点击,分析了执行顺序
这篇我们来看下 Intercept拦截

具体代码可以见https://github.com/2954722256/demo_event

在看之前, 我们先看一下 API

相关组件可以Override的方法

dispatchTouchEvent事件分发浅析(四)Intercept拦截_第1张图片
Paste_Image.png

前言

前面用到了 dispatchTouchEvent 和 onTouchEvent
分别表示 分发事件 和 触摸消费的事件
我们可以发现, Activity 和 View都只有这2个方法
在ViewGroup除了这2个方法以外, 还有一个 onInterceptTouchEvent 方法,
如果return true,表示拦截, 不向下传递了

我们看一下ViewGroup中
onInterceptTouchEvent 方法的实现

dispatchTouchEvent事件分发浅析(四)Intercept拦截_第2张图片
Paste_Image.png
public boolean onInterceptTouchEvent(MotionEvent ev) {
    return false;
}

简单总结
我们可以发现这里,
默认是return false, 不拦截
也就是说如果是直接extends ViewGroup,
return super.onInterceptTouchEvent(ev)
就是 return false
表示 不拦截


代码

TouchEventFather:

package com.aohuan.test.dodoevent.view;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;

import com.aohuan.test.dodoevent.tools.TouchEventUtil;


public class TouchEventFather extends LinearLayout {

    private final Context mContext;

    public TouchEventFather(Context context) {
        super(context);
        this.mContext = context;
    }

    public TouchEventFather(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.mContext = context;
//      this.setOnClickListener(new OnClickListener() {
//          @Override
//          public void onClick(View v) {
//              TouchEventUtil.doClick(TouchEventFather.class);
//          }
//      });
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        TouchEventUtil.logActionMsg(getClass(),"dispatchTouchEvent",ev);
        return super.dispatchTouchEvent(ev);
//      return false;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        TouchEventUtil.logActionMsg(getClass(),"onInterceptTouchEvent",ev);
        return super.onInterceptTouchEvent(ev);
//      return true;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        TouchEventUtil.logActionMsg(getClass(),"onTouchEvent",ev);
        return super.onTouchEvent(ev);
    }


}

TouchEventChilds:

package com.aohuan.test.dodoevent.view;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;

import com.aohuan.test.dodoevent.tools.TouchEventUtil;


public class TouchEventChilds extends LinearLayout {

    private final Context mContext;

    public TouchEventChilds(Context context) {
        super(context);
        this.mContext = context;
    }

    public TouchEventChilds(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.mContext = context;
//      this.setClickable(false);
//      this.setOnClickListener(new OnClickListener() {
//          @Override
//          public void onClick(View v) {
//              TouchEventUtil.doClick(TouchEventChilds.class);
//          }
//      });
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        TouchEventUtil.logActionMsg(getClass(),"onInterceptTouchEvent",ev);
        return super.onInterceptTouchEvent(ev);
//      return true;
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        TouchEventUtil.logActionMsg(getClass(),"dispatchTouchEvent",ev);
        return super.dispatchTouchEvent(ev);
//      return true;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        TouchEventUtil.logActionMsg(getClass(),"onTouchEvent",ev);
        return super.onTouchEvent(ev);
    }

}

TouchEventChilds2:

package com.aohuan.test.dodoevent.view;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;

import com.aohuan.test.dodoevent.tools.TouchEventUtil;


public class TouchEventChilds2 extends Button {

    Context mContext;

    public TouchEventChilds2(Context context) {
        super(context);
        this.mContext = context;
    }

    public TouchEventChilds2(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.mContext = context;
//        this.setClickable(false);
//        this.setOnClickListener(new OnClickListener() {
//            @Override
//            public void onClick(View v) {
//                TouchEventUtil.doClick(TouchEventChilds2.class);
//            }
//        });
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        TouchEventUtil.logActionMsg(getClass(),"dispatchTouchEvent",ev);
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        TouchEventUtil.logActionMsg(getClass(),"onTouchEvent",ev);
        return super.onTouchEvent(ev);
    }


}


代码简述

这3个类之间,没有直接关系,只是layout中简单的关系

dispatchTouchEvent事件分发浅析(四)Intercept拦截_第3张图片
Paste_Image.png

这里 TouchEventFather, TouchEventChild, TouchEventChild2
分别表示 【1】, 【2】, 【3】
我们可以分别设置值,和点击他们,来理解 Intercept拦截

dispatchTouchEvent事件分发浅析(四)Intercept拦截_第4张图片
Paste_Image.png

不设置 onInterceptTouchEvent时候

我们分别点击对应的位置 【1】【2】【3】
大家可以猜一猜对应的打印顺序。

点击【1】

MainActivity    ----    dispatchTouchEvent  ---->   ACTION_DOWN ---->   noMsg
TouchEventFather    ----    dispatchTouchEvent  ---->   ACTION_DOWN ---->   noMsg
TouchEventFather    ----    onInterceptTouchEvent   ---->   ACTION_DOWN ---->   noMsg
TouchEventFather    ----    onTouchEvent    ---->   ACTION_DOWN ---->   noMsg
MainActivity    ----    onTouchEvent    ---->   ACTION_DOWN ---->   noMsg

dispatchTouchEvent事件分发浅析(四)Intercept拦截_第5张图片
Paste_Image.png

点击【2】

MainActivity    ----    dispatchTouchEvent  ---->   ACTION_DOWN ---->   noMsg
TouchEventFather    ----    dispatchTouchEvent  ---->   ACTION_DOWN ---->   noMsg
TouchEventFather    ----    onInterceptTouchEvent   ---->   ACTION_DOWN ---->   noMsg
TouchEventChilds    ----    dispatchTouchEvent  ---->   ACTION_DOWN ---->   noMsg
TouchEventChilds    ----    onInterceptTouchEvent   ---->   ACTION_DOWN ---->   noMsg
TouchEventChilds    ----    onTouchEvent    ---->   ACTION_DOWN ---->   noMsg
TouchEventFather    ----    onTouchEvent    ---->   ACTION_DOWN ---->   noMsg
MainActivity    ----    onTouchEvent    ---->   ACTION_DOWN ---->   noMsg

dispatchTouchEvent事件分发浅析(四)Intercept拦截_第6张图片
Paste_Image.png

点击【3】

MainActivity    ----    dispatchTouchEvent  ---->   ACTION_DOWN ---->   noMsg
TouchEventFather    ----    dispatchTouchEvent  ---->   ACTION_DOWN ---->   noMsg
TouchEventFather    ----    onInterceptTouchEvent   ---->   ACTION_DOWN ---->   noMsg
TouchEventChilds    ----    dispatchTouchEvent  ---->   ACTION_DOWN ---->   noMsg
TouchEventChilds    ----    onInterceptTouchEvent   ---->   ACTION_DOWN ---->   noMsg
TouchEventChilds2   ----    dispatchTouchEvent  ---->   ACTION_DOWN ---->   noMsg
TouchEventChilds2   ----    onTouchEvent    ---->   ACTION_DOWN ---->   noMsg
dispatchTouchEvent事件分发浅析(四)Intercept拦截_第7张图片
Paste_Image.png

简单分析
·【1】是一个ViewGroup,所以会分发下去,再回传回去
·【2】是一个ViewGroup,所以同样会分发下去,再回传回去
·【3】是一个View,所以触发到OnTouchEvent后,就消费了
· 我们可以发现在 dispatch后面, 都会执行onIntercept方法
· 前面说过 return super.onInterceptTouchEvent(ev),就是 return false,所以之前都是return false,就是不拦截
·注意:这里【3】是Button的子类,点击会有点击效果
·(后面会设置拦截后,再注意观察)


添加onInterceptTouchEvent 拦截

要拦截,就只要Override对应ViewGroup的onInterceptTouchEvent方法,return true即可


TouchEventFather添加拦截

给TouchEventFather添加拦截,也就是对应的方法return true以后
对应的打印信息为:

MainActivity    ----    dispatchTouchEvent  ---->   ACTION_DOWN ---->   noMsg
TouchEventFather    ----    dispatchTouchEvent  ---->   ACTION_DOWN ---->   noMsg
TouchEventFather    ----    onInterceptTouchEvent   ---->   ACTION_DOWN ---->   noMsg
TouchEventFather    ----    onTouchEvent    ---->   ACTION_DOWN ---->   noMsg
MainActivity    ----    onTouchEvent    ---->   ACTION_DOWN ---->   noMsg
dispatchTouchEvent事件分发浅析(四)Intercept拦截_第8张图片
Paste_Image.png

我们可以发现,
到TouchEventFather后,就回传给MainActivity的onTouchEvent
后面对应的ViewGroup和View都没有获得到dispatchEvent


特殊测试

这个时候, 我们给TouchEventChilds2添加一个点击事件
因为TouchEventChilds2是继承Button的,所以点击很好测试

添加后,再次运行
对应的打印信息为:

MainActivity    ----    dispatchTouchEvent  ---->   ACTION_DOWN ---->   noMsg
TouchEventFather    ----    dispatchTouchEvent  ---->   ACTION_DOWN ---->   noMsg
TouchEventFather    ----    onInterceptTouchEvent   ---->   ACTION_DOWN ---->   noMsg
TouchEventFather    ----    onTouchEvent    ---->   ACTION_DOWN ---->   noMsg
MainActivity    ----    onTouchEvent    ---->   ACTION_DOWN ---->   noMsg
dispatchTouchEvent事件分发浅析(四)Intercept拦截_第9张图片
Paste_Image.png

我们可以发现,界面上面没有点击效果
打印信息中也没有点击信息
说明,点击事件被拦截了
(通过前几篇,我们也可以知道,先获得TouchListener,再获得onTouchEvent,再会有ClickListener, 现在拦截以后, 不会有对应的Touch事件了,更不会有Click事件了)


TouchEventChilds添加拦截

添加拦截后,对应的信息为:

MainActivity    ----    dispatchTouchEvent  ---->   ACTION_DOWN ---->   noMsg
TouchEventFather    ----    dispatchTouchEvent  ---->   ACTION_DOWN ---->   noMsg
TouchEventFather    ----    onInterceptTouchEvent   ---->   ACTION_DOWN ---->   noMsg
TouchEventChilds    ----    dispatchTouchEvent  ---->   ACTION_DOWN ---->   noMsg
TouchEventChilds    ----    onInterceptTouchEvent   ---->   ACTION_DOWN ---->   noMsg
TouchEventChilds    ----    onTouchEvent    ---->   ACTION_DOWN ---->   noMsg
TouchEventFather    ----    onTouchEvent    ---->   ACTION_DOWN ---->   noMsg
MainActivity    ----    onTouchEvent    ---->   ACTION_DOWN ---->   noMsg
dispatchTouchEvent事件分发浅析(四)Intercept拦截_第10张图片
Paste_Image.png

我们可以发现,
会dispatch到对应的拦截以后,就开始回传


简单总结

· onInterceptTouchEvent只有ViewGroup有,Activity和View都没有
· onInterceptTouchEvent在当前ViewGroup的dispatchTouchEvent之后执行,拦截后,就会从拦截的ViewGroup回传, 不会dispatch给下一层
· super.onInterceptTouchEvent(ev)默认返回false,所以return super.onInterceptTouchEvent(ev),就是 return false,就是不拦截


下一篇我们可以了解dispatchTouchEvent事件分发浅析(五)消费

你可能感兴趣的:(dispatchTouchEvent事件分发浅析(四)Intercept拦截)