案例讲解安卓的事件传递机制

来源:互联网 发布:centos7 yum安装git 编辑:程序博客网 时间:2024/06/05 00:45

首先关于安卓的事件传递机制我们需要知道一些东西:
View的继承关系,有关事件的几个方法:
这里写图片描述
跟Touch事件有关的处理方法主要有三个:
//分派事件
public boolean dispatchTouchEvent(MotionEvent ev)
//拦截事件
public boolean onInterceptTouchEvent(MotionEvent ev)
//处理事件
public boolean onTouchEvent(MotionEvent ev)

dispatchTouchEvent(MotionEvent event)            return true; //不再分发事件,表示拦截事件,拦截掉不会回传,事件在此消失            return false;//表示不做分发事件,事件不被拦截,回传给父控件的处理方法  return super.onTouchEvent() ;//事件传递机制,传递给自己的onTouchEvent方法。 onTouchEvent() return true; //自己处理消费掉事件,事件消费不再回传 return false;或者 return super.onTouchEvent() ;//效果一样,事件回传给父组件

这里写图片描述

举例说明:
可以参考csdn上的一个经典案例说明安卓的事件传递机制,简单而且精辟:
这是关于任务传递的故事:话说一家软件公司,来一个任务,分派给了开发经理去完成:
开发经理拿到,看了一下,感觉好简单,于是
开发经理:分派给了开发组长
开发组长:分派给了自己组员(程序员)
程序员:分派给了自己带的实习生。
实习生:好苦逼,无法分派,怎么办啊?只能自己干了
但是实习生能不能做好,有两种情况了。
情况一:
实习生:经过一段时间的研究,琢磨,熬夜,奋斗,死敲,皇天不负有心人啊,完成了。
后来又来一个类似的任务,也按着这样传递下去了(开发经理->开发组长->程序员->实习生),又有实习生完成了。
情况二:
实习生:经过一段时间的研究,琢磨,就是毫无头绪,无法完成,只能求教师傅(程序员)了。
程序员:啊,我怎么没留意就给实习生搞了,这任务好难啊,自己研究下,也没有头绪,没办法只能请求组长了。
开发组长:这任务不难啊,怎么我底下的人都不会了,没办法,只能自己搞了,经过,一段时间,完成了,感想,以后要是又有跟这个很类似的任务,我就自己弄了,不给他们弄了。
后来又来一个类似的任务,传递是这样的
开发经理:分派给开发组长
开发组长:啊,又是跟着上一个很类似的任务,我自己弄吧,没过多久也完成了!

根据上面的故事案例,我们可以新建几个类BossActivity(开发经理)、ManagerFrameLayout(开发组长)、ProgrammerRelativeLayout(程序员)、InternTextView(实习生)
BossActivity中的dispatchTouchEvent()和onTouchEvent();ManagerFrameLayout和ProgrammerRelativeLayout的dispatchTouchEvent()、onInterceptTouchEvent()、onTouchEvent();InternTextView的onTouchEvent()、dispatchTouchEvent()方法中编写打印日志的代码,查看内容。

这里写图片描述
事件一、点击红色按钮,查看log:

【开发经理】来一任务<按下>:需要{分派}给下一级【开发组长】来一任务<按下>:需要{分派}给下一级【开发组长】自己分派一任务<按下>:需要{拦截}吗?false【开发组长】自己{处理}任务<按下>:这任务怎么这么难,底下人都不会,还是自己干吧。                                                可是任务能解决嘛?false【开发经理】自己{处理}任务<按下>:连组长都不会,算了,这任务我还是自己来吧!false【开发经理】来一任务<离开>:需要{分派}给下一级【开发经理】自己{处理}任务<离开>:连组长都不会,算了,这任务我还是自己来吧!false

按下:
可以看到,整个事件是BossActivity先得到事件,调用它的dispatchTouchEvent分发事件,Activity返回值默认传递给ManagerFrameLayout,调用ManagerFrameLayout的dispatchTouchEvent方法,此时这个返回值默认return super.dispatchTouchEvent(event);默认的时候它会把事件传递给自己的onInterceptTouchEvent(MotionEvent event)拦截事件看自己是否需要拦截这个事件,但是由于它的返回值也是默return super.onInterceptTouchEvent(event);认,即没做拦截;事件继续传递,传递给自己的onTouchEvent(MotionEvent event)看自己是否处理这个事件; 自己的onTouchEvent(MotionEvent event)处理方法被调用,但是返回值也是默认,return super.onTouchEvent(event);自己并不处理事件。这样事件到了最里层的View也没有被消费,事件开始回传,回传给父容器Activity的onTouchEvent(MotionEvent event) ,Activity也是默认返回值,表示不做任何处理。整个过程事件都没有做处理和拦截,事件作废。
松开后:
看一下松开事件:由Activity的dispatchTouchEvent开始分发事件自己返回值是默认情况,把事件直接分发给自己的onTouchEvent(MotionEvent event)方法处理事件,自己返回值是默认情况,事件作废。 整个事件过程,并没有任何地方要处理事件, 由up事件log日志,也可以看到:最后松手时的事件,已经与ViewGroupOne没有任何关系。

事件二、点击绿色区域,查看log:

【开发经理】来一任务<按下>:需要{分派}给下一级【开发组长】来一任务<按下>:需要{分派}给下一级【开发组长】自己分派一任务<按下>:需要{拦截}吗?false【程序员】来一任务<按下>:需要{分派}给下一级【程序员】自己分派一任务<按下>:需要{拦截}吗?false【程序员】自己{处理}任务<按下>:实习生毕竟是实习生啊,还是自己干吧。可是任务能解决嘛?false【开发组长】自己{处理}任务<按下>:这任务怎么这么难,底下人都不会,还是自己干吧。                                                可是任务能解决嘛?false【开发经理】自己{处理}任务<按下>:连组长都不会,算了,这任务我还是自己来吧!false【开发经理】来一任务<离开>:需要{分派}给下一级【开发经理】自己{处理}任务<离开>:连组长都不会,算了,这任务我还是自己来吧!false

这里就会显而易见了。多了ProgrammerRelativeLayout,就多往下传递一层,最里面这层没做处理,最后还是回传回来。一直回传到activity事件全部消失

事件三、点击蓝色区域,查看log:

【开发经理】来一任务<按下>:需要{分派}给下一级【开发组长】来一任务<按下>:需要{分派}给下一级【开发组长】自己分派一任务<按下>:需要{拦截}吗?false【程序员】来一任务<按下>:需要{分派}给下一级【程序员】自己分派一任务<按下>:需要{拦截}吗?false【实习生】来一任务<按下>:需要{分派}给下一级吗?我想分派,我底下没人了,怎么办?我还是老老实实的干吧【实习生】自己{处理}任务<按下>:查阅资料,埋头苦干,一声不吭的干了起来。皇天就负有心人,无人为力,【没解决】。【程序员】自己{处理}任务<按下>:实习生毕竟是实习生啊,还是自己干吧。可是任务能解决嘛?false【开发组长】自己{处理}任务<按下>:这任务怎么这么难,底下人都不会,还是自己干吧。可是任务能解决嘛?false【开发经理】自己{处理}任务<按下>:连组长都不会,算了,这任务我还是自己来吧!false【开发经理】来一任务<离开>:需要{分派}给下一级【开发经理】自己{处理}任务<离开>:连组长都不会,算了,这任务我还是自己来吧!false

这个肯定在意料之中,不用解释也很清楚为何打印此log了。

增加处理:
事件一、蓝色区域,修改InternTextView代码,使得onTouchEvent方法return一个true,接下来就是查看点击蓝色区域,查看log:

【开发经理】来一任务<按下>:需要{分派}给下一级【开发组长】来一任务<按下>:需要{分派}给下一级【开发组长】自己分派一任务<按下>:需要{拦截}吗?false【程序员】来一任务<按下>:需要{分派}给下一级【程序员】自己分派一任务<按下>:需要{拦截}吗?false【实习生】来一任务<按下>:需要{分派}给下一级吗?我想分派,我底下没人了,怎么办?我还是老老实实的干吧【实习生】自己{处理}任务<按下>:查阅资料,埋头苦干,一声不吭的干了起来。皇天不负有心人,【解决了】。【开发经理】来一任务<离开>:需要{分派}给下一级【开发组长】来一任务<离开>:需要{分派}给下一级【开发组长】自己分派一任务<离开>:需要{拦截}吗?false【程序员】来一任务<离开>:需要{分派}给下一级【程序员】自己分派一任务<离开>:需要{拦截}吗?false【实习生】来一任务<离开>:需要{分派}给下一级吗?我想分派,我底下没人了,怎么办?我还是老老实实的干吧【实习生】自己{处理}任务<离开>:查阅资料,埋头苦干,一声不吭的干了起来。皇天不负有心人,【解决了】。

InternTextView的onTouchEvent(MotionEvent event)返回true的意思是,事件由我来处理。它处理了事件,就不可能出现回传了,出现这种log也是顺理成章了。再看UP事件与分发拦截是一致的。最后在InternTextView中消失。这个时候可以对比一了,一都是默认,可以称之为狭义的回传机制,而二的处理1:我们可以称之为狭义的拦截机制,每一次的往下分发,又可称为狭义的传递机制(称之为狭义,可能逼格略高些,是因为不能代表全部,却也不失一般性;最起码拦截与回传分发大致是什么很清楚了)。那接着就细致开来,从狭义走到广义。

事件二、蓝色区域,InternTextView的dispatchTouchEvent()返回一个true,查看log:

【开发经理】来一任务<按下>:需要{分派}给下一级【开发组长】来一任务<按下>:需要{分派}给下一级【开发组长】自己分派一任务<按下>:需要{拦截}吗?false【程序员】来一任务<按下>:需要{分派}给下一级【程序员】自己分派一任务<按下>:需要{拦截}吗?false【实习生】来一任务<按下>:需要{分派}给下一级吗?我想分派,我底下没人了,怎么办?我还是老老实实的干吧【开发经理】来一任务<离开>:需要{分派}给下一级【开发组长】来一任务<离开>:需要{分派}给下一级【开发组长】自己分派一任务<离开>:需要{拦截}吗?false【程序员】来一任务<离开>:需要{分派}给下一级【程序员】自己分派一任务<离开>:需要{拦截}吗?false【实习生】来一任务<离开>:需要{分派}给下一级吗?我想分派,我底下没人了,怎么办?我还是老老实实的干吧

InternTextView的dispatchTouchEvent(MotionEvent event)返回值为true,表示不再分发事件也可以说是拦截事件。此时InternTextView的onTouchEvent方法不会被调用,既然是拦截了事件也不会回传。

事件三、蓝色区域,InternTextView的onTouchEvent()方法被return一个false,查看log:

【开发经理】来一任务<按下>:需要{分派}给下一级【开发组长】来一任务<按下>:需要{分派}给下一级【开发组长】自己分派一任务<按下>:需要{拦截}吗?false【程序员】来一任务<按下>:需要{分派}给下一级【程序员】自己分派一任务<按下>:需要{拦截}吗?false【实习生】来一任务<按下>:需要{分派}给下一级吗?我想分派,我底下没人了,怎么办?我还是老老实实的干吧【实习生】自己{处理}任务<按下>:查阅资料,埋头苦干,一声不吭的干了起来。皇天就负有心人,无人为力,【没解决】。【程序员】自己{处理}任务<按下>:实习生毕竟是实习生啊,还是自己干吧。可是任务能解决嘛?false【开发组长】自己{处理}任务<按下>:这任务怎么这么难,底下人都不会,还是自己干吧,可是任务能解决嘛?false【开发经理】自己{处理}任务<按下>:连组长都不会,算了,这任务我还是自己来吧!false【开发经理】来一任务<离开>:需要{分派}给下一级【开发经理】自己{处理}任务<离开>:连组长都不会,算了,这任务我还是自己来吧!false

事件四、蓝色区域,InternTextView的dispatchTouchEvent()返回一个false,查看log:自己估计一下,跟上面差不多,只不过没有走onTouchEvent方法
上边都是针对蓝色区域点击;这是因为,只有点击了蓝色位置,事件才有可能传递到InternTextView,点击其他位置根本不会调InternTextView的任何方法。

同样,点击绿色和红色区域也可以按照上面的思路想到对应的结果,在这里我们不作讨论,事件传递机制大概就是这样,需要慢慢消化下~