Android 事件分发机制——以Demo实例了解

前言

网上很多关于事件分发的原理、源码分析、流程图解析等等,有些说的比较清楚,有些只是借鉴他人并添加自己的理解,在这里就不对原理神马的进行分析啦,直接通过一个ViewGroup和View来进行探讨

因为只是简单测试,所以就没有写的那么的严谨

1.代码+注释

DecoreViewGroup 

public class DecoreViewGroup extends ViewGroup{


    public DecoreViewGroup(Context context) {
        super(context);
    }

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

    public DecoreViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public DecoreViewGroup(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            measureChild(getChildAt(i), widthMeasureSpec, heightMeasureSpec);
        }
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int childCount = getChildCount();
        int layoutWidth = r-l;
        int left = 0;
        int right = 0;
        int top = 0;
        for (int i = 0; i < childCount; i++) {
            View view = getChildAt(i);
            // 换行:比较right,right如果大于Layout宽度,那么要换行
            right = left + view.getMeasuredWidth();
            if (right > layoutWidth) {
                left = 0;
                right = left + view.getMeasuredWidth();
                top += view.getMeasuredHeight();
            }
            getChildAt(i).layout(left, top, right, top + view.getMeasuredHeight());
            left += view.getWidth();
        }
    }

    /**
     * onInterceptTouchEvent 返回true  自己消费 子类收不到
     *                       返回false 子类消费
     * @param event
     * @return
     */
    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        Log.d("touchTest", "ViewGroup onInterceptTouchEvent ==="+ getDispatchSize(event.getAction()) + super.onInterceptTouchEvent(event));
        return super.onInterceptTouchEvent(event);
    }


    /**
     * dispatchTouchEvent    返回true  自己也消费不到
     *                       返回false 自己可以消费
     *                       返回super.dispatchTouchEvent(event) 默认为false
     * 但是如果返回false , 就一定要调用super.dispatchTouchEvent(event)方法哦
     * 否则的话onTouchEvent方法还是收不到
     * @param event
     * @return
     */
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.d("touchTest", "ViewGroup dispatchTouchEvent ======"+ getDispatchSize(event.getAction()) + super.dispatchTouchEvent(event));
        return super.dispatchTouchEvent(event);
    }

    public String getDispatchSize(int patch){
        return patch == 0 ? "点击====" : patch == 1? "抬起====" : patch == 2 ? "移动====" : "其他====";
    }

    /**
     * onTouchEvent    返回true  向上传递,将执行所有的事件
     *                 返回false 自己消费 不向上传递 执行DOWN事件之后不再执行(只有点击事件)
     *                 返回super.dispatchTouchEvent(event) 默认为false , 返回 super.onTouchEvent(event)才能收到点击事件
     * @param event
     * @return
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.d("touchTest", "ViewGroup onTouchEvent ============"+ getDispatchSize(event.getAction())+ super.onTouchEvent(event));
        return  super.onTouchEvent(event);
    }
}

DecoreView 

 

public class DecoreView extends View {


    public DecoreView(Context context) {
        super(context);
    }

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

    public DecoreView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public DecoreView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }
    public String getDispatchSize(int patch){
        return patch == 0 ? "点击====" : patch == 1? "抬起====" : patch == 2 ? "移动====" : "其他====";
    }

    /**
     * 控制自己
     * dispatchTouchEvent    返回true  自己也消费不到
     *                       返回false 自己可以消费
     *                       super.dispatchTouchEvent(event) 默认false 自己可以消费
     * 但是如果返回false , 就一定要调用super.dispatchTouchEvent(event)方法哦
     * 否则的话onTouchEvent方法还是收不到
     * 如果返回true就不用啦,因为已经被强制拦截啦
     * @param event
     * @return
     */
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.d("touchTest", "View dispatchTouchEvent ==========="+ getDispatchSize(event.getAction()) + super.dispatchTouchEvent(event));
        return super.dispatchTouchEvent(event);
    }

    /**
     * onTouchEvent    返回true  向上传递,将执行所有的事件 ,但是不会执行onclick()方法
     *                 返回false 自己消费 不向上传递 不会执行onclick
     *                 返回super.dispatchTouchEvent(event) 默认为false , 会执行onClick
     * 子view的onTouchEvent没有返回True。则最后还是由ViewGroup去消费此事件
     * @param event
     * @return
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.d("touchTest", "View onTouchEvent =================" + getDispatchSize(event.getAction()) + super.onTouchEvent(event));
        return super.onTouchEvent(event);
    }
}

代码大家直接copy到一个Demo中就行啦,有简单的一些注释,可以通过log来查看设置不同的返回值所执行的顺序

包装很简单,直接将DecoreView 套在DecoreViewGroup下就行啦,并设置不同的背景颜色来区分区域

在尝试了一上午之后,开始写写我对事件分发的理解

我的理解

(1).Activity中重写dispatchTouchEvent()

假如在activity中添加这么一段,那你activity下的所有控件都收不到点击事件啦

@Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        return true;
    }

dispatchTouchEvent主要是用来给自己分发的,感觉有点像ViewGroup中的onInterceptTouchEvent()

  • true:简单来说就是我想要这个事件,你不要继续分发下去了,就由我来消费这个事件,所以你点击控件相当于被activity          拦截了,你永远收不到事件

  • false:我不拦截啦,你继续往下走吧

  • super.dispatchTouchEvent():默认值就是false哟,相当于默认就不拦截,但是父类中的dispatchTouchEvent()方法还有         很多事情要处理,所以最好不要返回false,要不就返回true,要不就返回super.dispatchTouchEvent()

(2).ViewGroup中重写onInterceptTouchEvent()

onInterceptTouchEvent()方法主要是用来给子View分发的

  • true:子View的所有的事件分发回调都不会调用了,相当于隔绝了

  • false | super.dispatchTouchEvent():子View可以正常接收回调,不拦截继续向子View分发

(3).ViewGroup中重写dispatchTouchEvent()

  • true:将不会再调用onTouchEvent()方法啦,自己的事件回调已经被拦截掉了

  • super.dispatchTouchEvent() | false:继续向下分发

(4).ViewGroup中重写onTouchEvent()

  • super.dispatchTouchEvent() | true:如果在View设置了true,ViewGroup只能收到一次onTouchEvent的ACTION_UP事件,但是可以收到               dispatchTouchEvent->onInterceptTouchEvent事件,相当于会向上传递给ViewGroup的事件

  • false:只有返回false ,ViewGroup中onTouchEvent才能收到事件,由dispatchTouchEvent->onInterceptTouchEvent->onTouchEvent

(5).View中重写dispatchTouchEvent()

  • true:将不会再调用onTouchEvent()方法啦,自己的事件回调已经被拦截掉了

  • super.dispatchTouchEvent() | false:继续向下分发,下一步是onTouchEvent

(6).View中重写onTouchEvent()

  • super.dispatchTouchEvent() | true:如果在View设置了true,ViewGroup只能收到一次onTouchEvent的ACTION_UP事件,但是可以收到               dispatchTouchEvent->onInterceptTouchEvent事件,相当于会向上传递给ViewGroup的事件

  • false:只有返回false ,ViewGroup中onTouchEvent才能收到事件,由dispatchTouchEvent->onInterceptTouchEvent->onTouchEvent

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值