安卓事件分发

一、事件分发的相关方法

1、事件分发相关的方法:

    1、dispatchTouchEvent 事件分发
    2、onInterceptTouchEvent 事件拦截 (只有ViewGroup有)
    3、onTouchEvent 事件处理

2、三个方法的作用:

既然要分析三个方法的作用,那么肯定要分析三个方法的方法内容与返回值了。
① onInterceptTouchEvent
先讲最简单的(只有ViewGroup中有),onInterceptTouchEvent方法的返回值表示当前ViewGroup是否要拦截事件,一旦拦截(返回true),那么本系列事件就不会分发到ViewGroup的子View中去(也有例外,在这先不讨论例外情况,先从最简单的开始理解)。那么,onInterceptTouchEvent的方法体中应该干嘛呢?也很简单,就是来判断什么时候应该让ViewGroup拦截事件。onInterceptTouchEvent的返回值默认是false(不拦截),也就是说,如果我们不去重写这个方法的话,它默认返回false(不拦截事件)。

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        boolean intercept = false;
        if(xxx){ //应该让ViewGroup拦截事件的条件
            intercept = true;
        }
        return intercept;
    }
  • 1

② onTouchEvent
这个方法也很简单,它的方法体是对事件的具体处理,返回值表示处理该事件(其实它的返回值没有太大意义,等具体分析dispatchTouchEvent时会说明该返回值的意义)。

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch(event.getAction()){
            case MotionEvent.ACTION_DOWN:
                //处理手指摁下的操作
            break;

            case MotionEvent.ACTION_MOVE:
                //处理手指移动的操作
            break;

            case MotionEvent.ACTION_UP:
                //处理手指抬起的操作
            break;    
        }

        return true;
    }
  • 1

③ dispatchTouchEvent
这个方法是整个事件分发的核心方法,dispatch英文名是分发的意思。那么它的方法内容和方法返回值又是什么呢?起什么样的作用呢?先来说说返回值,dispatchTouchEvent的返回值才是决定该View或者ViewGroup能否获得该事件的关键。

dispatchTouchEvent的返回值:
————返回true,上层的事件会依次传递下来,返回false,则上层的事件只会传递DOWN事件下来(当然,所有这些的前提是上层的ViewGroup没有拦截事件,因为一旦上层ViewGroup拦截了事件,那么下面的控件都不会接收到事件了)。
注意:dispatchTouchEvent虽然是分发事件的方法,但是其boolean返回值不是“是否要往下分发事件”的意思,而是“我是否需要接收该事件”的意思,是告诉上层ViewGroup是否要将事件传递给我

怎么理解呢?可以用一段白话文来帮助我们理解:
首先,ViewGroup的“上面”会问:“你是否需要该系列事件?”,即“上面”会通过自己的dispatchTouchEvent方法将“DOWN”事件分发传递进ViewGroup进行询问(这里可以将DOWN事件当作一名询问官),如果ViewGroup告诉“上面”:“我需要,你把事件都给我吧(即ViewGroup自己的dispatchTouchEvent返回true时)”。这时,“上面”会将该系列的事件依次传递进ViewGroup,ViewGroup拿到事件要怎么处理,就看ViewGroup自己的dispatchTouchEvent方法的方法体的实现了,一般调用super.dispatchTouchEvent按照系统的事件分发机制去处理,此时ViewGroup也会先去询问它的child:“你是否需要该组事件?”,即ViewGroup将“DOWN”传进子View去询问,如果子View的dispatch返回true,则说明子View需要,所有的事件都会通过ViewGroup再传给子View,此时,事件会从最上面一直传递给ViewGroup的dispatchTouchEvent再到子View的dispatchTouchEvent,如果子View的dispatchTouchEvent方法调用了super.dispatchTouchEvent(ev),则会调取子View的onTouchEvent的回调方法(本文只讨论这三大方法,不讨论在外面调用setOnTouchListener和setOnClickListener方法)。

dispatchTouchEvent默认时的伪代码:

    ViewGroup的
    public boolean dispatchTouchEvent(MotionEvent ev){
        boolean consume = false;
        if(onInterceptTouchEvent(ev)){ //先判断是否拦截、拦截就直接执行自己的onTouchEvent方法
            consume = onTouchEvent(ev);
        }else{ //如果不拦截、则执行子View或者ViewGroup的dispatchTouchEvent方法
            consume = child.dispatchTouchEvent(ev);
        }
        return consume;
    } 

    View的
    public boolean dispatchTouchEvent(MotionEvent ev){
        boolean consume = onTouchEvent(ev);
        return consume;
    } 
  • 1

从上面代码View的dispatchTouchEvent可以看到,为什么onTouchEvent也要有一个返回值,那是因为在dispatchTouchEvent的默认方法体中会调用onTouchEvent方法,并且onTouchEvent的返回值会影响到dispatchTouchEvent方法的返回值。如果我们重写dispatchTouchEvent方法:

    public boolean dispatchTouchEvent(MotionEvent ev){
        super.dispatchTouchEvent(ev);
        return true;
    } 
  • 1

此时事件仍然按照系统的分发机制去传递事件,但是dispatchTouchEvent的返回值已经写死了为true,那么此时,onTouchEvent方法的返回值就没有任何意义了。

3、事件分发相关的方法的默认代码:

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

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return super.onTouchEvent(event);
    }
  • 1
所有的方法都只是调用了super的同名方法

方法  dispatchTouchEvent(MotionEvent ev)中的super.dispatchTouchEvent(ev);就是调用的View或者ViewGroup的dispatchTouchEvent方法,即分发事件。只有调用了super.dispatchTouchEvent才会根据系统的分发逻辑去分发事件。

方法  onInterceptTouchEvent(MotionEvent ev)中的super.onInterceptTouchEvent(ev);
父类ViewGroup默认返回false,即不拦截。
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return false; //默认值为false
    }
  • 1
方法  onTouchEvent(MotionEvent event)中的super.onTouchEvent(event);是处理事件。

二、结合例子

例1

ViewGroup代码(使用默认的):

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

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return super.onTouchEvent(event);
    }
  • 1

View的代码:

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return true;
    }
  • 1

只重写了View的onTouchEvent方法,返回true。
此时的分发逻辑:(分发只看dispatchTouchEvent方法)

1、由于View的onTouchEvent返回true,而View的dispatchTouchEvent方法使用的默认的super.dispatchTouchEvent(event) ,由于super.dispatchTouchEvent(event)中会调用onTouchEvent方法,返回值也受onTouchEvent方法返回值影响(可以根据上面的事件分发伪代码可以看出此处是相同的返回值),所以View的dispatchTouchEvent方法返回值为true。

2、因为ViewGroup的dispatchTouchEvent使用的默认,根据伪代码,它没有拦截事件,那么返回值就是子View的dispatchTouchEvent的返回值,因此ViewGroup的dispatchTouchEvent也返回true

3、当ViewGroup的“父ViewGroup”的“DOWN”来询问ViewGroup是否需要该组事件时,由于ViewGroup的dispatchTouchEvent返回true,因此ViewGroup表示需要该组事件,那么上面会将一系列的事件全部传入ViewGroup的dispatchTouchEvent中。

4、当ViewGroup拿到事件时,由于它调用了super.dispatchTouchEvent(event),所以它会遵循系统的分发机制先去询问子View是否需要该组事件,子View的dispatchTouchEvent返回了true,因此子View表示需要该组事件,那么ViewGroup会将一系列的事件传入子View的dispatchTouchEvent中。

5、由于子View的dispatchTouchEvent调用了super.dispatchTouchEvent(event),那么最终调用了子View的onTouchEvent方法,所有的事件都会在子View的onTouchEvent中去处理。

例2

ViewGroup代码(使用默认的):

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

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return super.onTouchEvent(event);
    }
  • 1

View的代码:

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        super.dispatchTouchEvent(event);
        return true;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // 处理事件
        return false;
    }
  • 1

这里重写了View的dispatchTouchEvent方法和onTouchEvent方法
此时的分发逻辑:

此时,View的onTouchEvent虽然返回false(我不处理事件),但是View的dispatchTouchEvent方法的返回值为true不受你 onTouchEvent返回值的影响,又dispatchTouchEvent方法体中调用了super.dispatchTouchEvent(event),因此所有的事件还是会传递进onTouchEvent方法中去(与你onTouchEvent的返回值无关,不管你是否要处理事件都得处理)。

例3

ViewGroup代码(使用默认的):

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        super.dispatchTouchEvent(ev);
        return false;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return super.onTouchEvent(event);
    }
  • 1

View的代码:

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        super.dispatchTouchEvent(event);
        return true;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // 处理事件
        return false;
    }
  • 1

这里重写了ViewGroup的dispatchTouchEvent方法,View的dispatchTouchEvent方法和onTouchEvent方法
此时的分发逻辑:

由于ViewGroup的dispatchTouchEvent方法的返回值也是写死的为false,那么“上面”的DOWN事件传递下来询问ViewGroup是否需要事件时,ViewGroup拒绝消耗事件,上面就不会再传递事件下来了。此时,虽然子View的dispatchTouchEvent返回true,也是拿不到所有事件的。
这时,所有的事件只有DOWN事件会从“最上面”传递到ViewGroup的dispatchTouchEvent方法(因为DOWN相当于询问官来询问你是否需要的,不管你dispatchTouchEvent返回true还是false,DOWN都会传下来,当然有一种情况,就是ViewGroup将事件直接拦截了,那DOWN都不会传递下来了),然后传递给子View的dispatchTouchEvent方法,子View的dispatchTouchEvent将DOWN事件传递给自己的onTouchEvent。之后的所有事件都不会再传递下来了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

春哥一号

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值