安卓事件分发

来源:互联网 发布:手机室内建模软件 编辑:程序博客网 时间:2024/06/05 09:38

一、事件分发的相关方法

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;    }

② 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;    }

③ 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;    } 

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

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

此时事件仍然按照系统的分发机制去传递事件,但是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);    }
所有的方法都只是调用了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    }
方法  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);    }

View的代码:

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

只重写了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);    }

View的代码:

    @Override    public boolean dispatchTouchEvent(MotionEvent event) {        super.dispatchTouchEvent(event);        return true;    }    @Override    public boolean onTouchEvent(MotionEvent event) {        // 处理事件        return false;    }

这里重写了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);    }

View的代码:

    @Override    public boolean dispatchTouchEvent(MotionEvent event) {        super.dispatchTouchEvent(event);        return true;    }    @Override    public boolean onTouchEvent(MotionEvent event) {        // 处理事件        return false;    }

这里重写了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。之后的所有事件都不会再传递下来了。

本文没有讨论子View中调用getParent().requestDisallowInterceptTouchEvent(true)来忽略ViewGroup的事件拦截,重点只是讨论的dispatchTouchEvent方法,如果要深入研究可以参考其他文章

1 0
原创粉丝点击