您的位置:首页 > 移动开发 > Android开发

安卓事件分发

2016-06-29 14:18 471 查看

一、事件分发的相关方法

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:
//处理手指抬起的操作
brea
4000
k;
}

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方法,如果要深入研究可以参考其他文章
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android