android中事件分发机制

开篇

本文内容主要是对android中事件分发机制进行一些讲解,也就是个人对事件分发过程的一些理解,谈不上讲解吧。 本文中内容参考了《开发艺术探索》还有xiaanming大神博客中的内容,加上自己的理解,如有不对的请不吝赐教。


首先介绍一些需要了解的基础知识和方法。只有懂得了这些才能更好的理解事件分发的过程;

事件及事件序列:一个MotionEvent就代表这一个事件,事件的种类有很多,down,up,move….等。 事件序列是指从一个从点击屏幕开始到离开屏幕结束,这其中所产生的一系列的事件所组成的就是事件序列。

三种方法:

dispatchTouchEvent(),用于进行事件的分发,dispatch单词本身就是分发,派遣的意思,如果事件能够传递到当前的View那么此方法一定会被调用,返回值受当前View的onTouchEvent和下级的dispatchTouchEvent的返回值影响,来表示是否消耗事件,通常在使用的时候此方法不需要重写,除非有特殊的需求(目前我是没有 重写过。。。)

onInterceptTouchEvent(),在上述方法中调用,用来判断是否拦截某个事件(这里注意是事件,而不是整个事件序列),如果当前View拦截了某个事件,那么之后的在同一个事件序列中的其他事件不会重复调用此方法,因为你已经决定拦截,就不会再询问你时候要拦截。此方法的返回值表示时候拦截事件,true则拦截,false不拦截。

onTouchEvent(),用于进行事件的处理,在决定拦截事件之后会被调用。返回结果表示是否消耗当前事件。如果不消耗,则同一事件序列中吗,当前View不会再次接收到事件。 下面是《开发艺术探索》书中的代码。

public boolean dispatchTouchEvent(MotionEvent event) {
boolean consume =false;
if(onInterceptTouchEvent(event)){
consume=onTouchEvent(event);
}else{
consume=child.dispatchTouchEvent(event);
}
return consume;
}

这个下了个MarkdownPad编辑器还不会用了。。。真是笨啊,不知道上面代码片看起来怎么样。
梳理下这个代码的流程,首先当事件传递到当前View的时候回调用dispatchTouchEvent这个方法,之后如果这个ViewGroup的onInterceptTouchEvent返回值是true的话就表示这个ViewGroup要拦截这个事件,即它的onTouchEvent这个方法会被调用,如果onInterceptTouchEvent返回值为false的话,则表示它不拦截这个事件,当前事件就会继续传递给它的子元素,接着子元素的dispatchTouchEvent这个方法会被调用,如此反复直到事件被处理。

事件分发流程

当一个点击事件产生后,它的传递顺序是从Activity->Window->View,即事件从事先传到Activity,再传递给Window,最后再传递给顶级View,顶级View在接收到点击事件之后就会按照事件分发机制取分发事件。当然也得考虑一种情况,如果View的onTouchEvent返回值是false的话,那么事件就会交给它的父容器来处理,以此类推,我们可以得出这样的一个结论,事件分发的过程是由最外边的往里面传,一直传到最里面,如果这个过程中,所有的View都不消耗掉这个事件,那么这个事件就会从最里面往外面传递,调用父容器的onTouchEvent方法,如果所有的父容器也都不消耗这个事件的话,那么最终这个事件就又回到Activity。

当然了,事件分发流程肯定不能像上文说的那么简单,如果这么简单也不是迈向高级安卓程序员的必经之路了,虽然大体上的流程就是这样的,不过还会有几个因素来影响到这个事件的分发,接下来就我知道的几种会对事件分发产生影响的情况进行分析。

  1. 子View的onTouch方法,当一个View需要处理事件的时候,它的onInterceptTouchEvent方法会返回true,表示拦截事件,如果它设置了OnTouchListener的话,那么会执行其中的OnTouch方法,对于OnTouch方法来说有一个boolean的返回值,表示是否会继续执行onTouchEvent这个方法,返回值为true,表示拦截事件不进行传递了,onTouchEvent方法就不会调用,false则相反。
  2. 对于子View来说,如果当前设置了onClickListener的话,那么会在onTouchEvent方法后执行,其实也不应该说在之后执行,应该说如果在onTouchEvent方法中能够同时接收到down和up事件的话,那么会调用它的onClick方法(如果有设置监听的话)。更复杂的是如果还设置了onLongClickListener的话,也就是说同一个View现在有三个监听器,onTouch,onClick,onLongClick,这样的话事件又应该是怎么执行的那?请看第三点。
  3. 对于用一个View的多个监听器的执行顺序和拦截方式。只列举三onTouch,onClick,onLongClick,这三种监听同时存在的时候的调用顺序是,onTouch->onTouchEvent(onLongClick->onClick)注意到我把click和longClick事件都写在onTouchEvent这个方法里面了,是因为这两个方法都是在,onTouchEvent中被调用的,而且LongClick会在Click之前调用,根据之前的理论我们可以得出这样的一个结论,如果onTouch方法的返回值为True,那么不会执行onTouchEvent方法,也就不会执行其中onLongClick和onClick了。之后如果在onLongClick方法中的返回值为true的话就不会继续执行onClick事件,因为之前碰过到执行onLongClick之后又执行onClick事件,可以选择在onLongClick方法中返回true来屏蔽onClick方法。
  4. View的enable属性不影响onTouchEvent方法的返回值,就是说如果当前View是不可用的,但是只要它的clickable或者longClickable有一个为true的话,它的onTouchEvent就会返回true,消耗掉这个事件。
  5. 正常情况下,一个事件序列只能被一个View拦截并消耗,因为一旦一个元素拦截了这个事件,那么之后同一个事件序列中的其他事件都会交给它来处理,而且对于ViewGroup来说还不会重复调用onInterceptTouchEvent方法来询问是否拦截事件。但是我们可以通过一些其他的方式来实现同一个事件由两个View共享。比如可以在拦截的onTouchEvent方法中强行调用其他View的onTouch方法使得事件能够传递到其他的View。也可以在onTouchEvent的方法中进行事件的处理,之后将返回值设置成false这个对于这个事件来说它的父容器应该也可以继续使用这个事件(这种情况好像并没有消耗掉这个事件?方法有待商榷)。
  6. 对于一个View来说,当事件传递到它的时候如果他决定不拦截ACTION_DOWN事件的话,那么之后的同一序列中的其他事件都不会传递给它,世上没有后悔药,错过就是错过,无法挽回了。在想要除非等遇到下一个人吧。。。这个最明显也是最容易犯的错误就是在listView的Item中存在能够获得点击事件的控件,这样当你设置onItemClickListener的时候这个方法使不会执行的,因为这个事件到你的时候你没有珍惜,被item中的某一个控件给消耗掉了,直到失去的时候追悔莫及,晚了,所以可以将item中能够获得事件的控件设置clickable属性为false,就可以
  7. ViewGroup默认是不拦截事件的,就是说它的onInterceptTouchEvent方法默认返回值为false,view的longClickable默认是false,clickable则要分情况,比如button和textView就是不同的。
  8. 通过requestDisallowInterceptTouchEvent方法可以设置一个标记位来影响父元素对事件的分发,这个方法的含义就是告诉父容器,这个事件我要了,请你不要对我进行干预了。(当然也得它能够收到这个事件才可以)

以上的8点是我参考书中的介绍和看别人博客总结的,如果有不对的可以给我留言相互探讨。

了解事件分发的目的

个人认为了解事件分发的目的有一下几点:

  1. 作为android中交互中的最重要的一环,我们的app就是通过事件分发才能与用户进行交互,之后当获得到事件之后才能继续执行后台的代码,所以我们有必要弄清楚,当用户的手指触摸屏幕的时候,android都在干些什么事情,只有充分了解了分发的流程之后我们才能去控制这个流程来达到我们想要的目的。
  2. 自定义View的必备知识。自定义View是我认为android中最具有魅力和想象力的一个地方,你完全可以根据你的想法,思路,业务,喜好,等等去自己设计一个View当然前提是你得对View中的知识进行充分的了解和认知。而其中事件分发是很重要的一环。
  3. 解决滑动冲突的途径。当我们在写app的时候不可避免的会碰到各种滑动冲突的问题。事件分发是解决滑动冲突的最根本的方法。只有充分了解机制之后,才可以根据不同的事件,通过不同的限制条件来决定事件的分发。
  4. 关于具体的源码分析可以去看xiaanming的博客,其中讲的很好,最后还是去买书吧。

参考资料

  1. 推荐大家去买一本之后一直在推荐的书,任玉刚先生的《开发艺术探索》,强烈推荐。
  2. 推荐大家可以去看xiaanming的博客,链接在下面,其中对事件的分发进行了充分的例子展示。
    http://blog.csdn.net/xiaanming/article/details/21696315

那么今天的博客就到这里了,虽然讲的不多,但绝对是本人一字一字敲出来的,如果有不对的地方可以留言,之后的博文估计会有一些网络框架的自定义View方面的东西,大家加油吧!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值