浅谈Android事件分发机制(一)点击事件的传递规则

来源:互联网 发布:关于网络诈骗的作文800 编辑:程序博客网 时间:2024/04/27 02:07

事件分发,我想对于很多开发者来说都是很头疼的,毕竟很难理解,也很让人头痛,不管是中级还是高级工程师,对于事件分发,都多多少少有点说不出来的感觉,虽然他很难理解,我们也需要去了解它,认识它,从而掌握它,对于我们需要进阶到中级甚至高级工程师需要写自定义控件的时候,Android的事件分发就格外重要了,今天我们就借这个主题来了解一下什么是事件分发?

在写这篇文章的时候我已经学习了很久的事件分发,为了弄清楚它的工作原理,我也费了很大的劲:

要了解点击事件的传递规则,首先我们要了解MotionEvent,因为它才是点击事件的主体,那么MotionEvent是什么?它主要是来干嘛的?我们接着往下说,MotionEvent其实就是手指接触屏幕所产生的一系列事件,但是我们用得最多的也就是下面三个事件:

  • 1、ACTION_DOWN——————-手指刚接触到屏幕
  • 2、ACTION_MOVE——————–手指在屏幕上移动
  • 3、ACTION_UP————————手指松开屏幕的一瞬间

手指在正常情况下,一次手指触摸屏幕的行为会触发一系列事件,但是我们只考虑如下几种情况:

  • 1、正常点击屏幕后离开松开,事件的序列为:DOWN——->UP
  • 2、点击屏幕华东一会在松开,事件序列为:DOWN——->MOVE———>UP

以上情况都是典型的事件序列,好了,回到正题,我们在这里主要还是讲解事件分发。
所谓事件分发,其实就是对MotionEvent事件的分发过程,即当一个MotionEvent产生以后,系统需要把这个事件传递给下一个具体的View,而这个传递的过程就是分发过程,而点击事件的分发过程由三个很重要的方法来共同完成,即:dispatchTouchEvent(MotionEvent ev)、onInterceptTouchEvent(MotionEvent ev)、onTouchEvent(MotionEvent ev),下面我主要把这几个方法的作用来说一下:

  1. public boolean dispatchTouchEvent(MotionEvent ev)用来进行时间消耗,消耗的意思就是View本身是否需要去对他进行一个消耗,如果返回true,则进行消耗,只要事件能传递到View,那么此事件一定会调用,他是事件分发的基础,也是入口,通过它才能将事件往下分发。它的返回结果受View的onTouchEvent和下级View的dispatchTouchEvent方法的影响
  2. public boolean onInterceptTouchEvent(MotionEvent ev)此事件只有在ViewGroup中才有,View中是没有这个事件的,用来表示是否拦截此事件,如果当前View拦截了此事件,那么在同一个时间序列当中,此方法不会再被调用
  3. public boolean onTouchEvent(MotionEvent ev)在dispatchTouchEvent中调用,用来处理点击事件,返回结果表示是否消耗当前事件,如果不消耗,则在当前序列中View无法再接收到此事件,也就是说他执行的前提条件是当前View需要消耗,并且拦截当前事件才会执行onTouchEvent事件

那么上面的三个方法到底是什么关系呢???是不是有点迷了?其实刚开始的时候我也很迷,但是仔细了解一下,就会发现他们之间的一些区别了,我可以用一段伪代码来描述一下他们的具体关联:

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

上面的代码,已经把三者的关系表现的非常淋漓尽致了,通过上面的伪代码,我们也可以了解点击事件的传递规则:对于一个ViewGroup来说,点击事件产生后,首先会传递给它本身,这个时候他的dispatchTouchEvent就会被调用,如果这个ViewGroup的onInterceptTouchEvent方法返回true,就表示她要拦截当前事件,接着事件就会交给ViewGroup处理,也就是他的onTouchEvent方法就会被调用;如果返回false,就表示他不拦截当前事件,此时当前事件就会出递给他的子元素即子View,接着子View的dispatchTouchEvent方法就会被调用,如此反复直到事件处理结束。

如果这个时候View设置了OnTouchListener监听,那么OnTouchListener中的onTouch方法会被先进行调用,这时候事件的处理还要看onTouch的返回值,如果返回false,则View的onTouchEvent方法就会被调用,如果返回true,那么onTouchEvent方法将不会被调用,由此可见,给View设置的OnTouchListener,它的优先级比onTouchEvent要高,在onTouchEvent方法中,如果设置的有OnClickListener,那么他的onClick方法会被调用,所以说我们平时常用的OnClickListener,其优先级最低,在事件处理的最后才进行处理。

当一个点击事件产生后,它的传递过程遵循如下顺序:Activity->Window->View ,事件总是先传递给Activity,Activity在传递给Window,最后Window在传递给顶级View,顶级View接受到事件后,就会按照事件分发机制去分发事件,这里我们在考虑一种情况,如果一个View的onTouchEvent返回false,那么它的父容器的onTouchEvent将会被调用,如果所有元素都不处理这个事件,那么这个事件最终会交给Activity去处理,就是Activity的OnTouchEvent方法会被调用。

关于事件传递机制,这里给出一些总结,这些需要大家去理解,只有理解了,才能掌握事件分发的规则:

  • 1、同一个时间序列是从手指触摸屏幕的那一刻起,到手指离开屏幕的那一刻结束,这个中间所产生的一系列事件,这个事件的序列是以DOWN事件开始,中间含有数量不定的MOVE事件,最后以UP事件结束
  • 2、正常情况下,一个时间序列只能被一个View拦截且消耗。因为一旦一个View拦截了某事件,那么同一个序列中的事件内的所有事件都会交给他处理,因此同一个序列中的事件就不能分别由两个View同时处理,但是通过特殊手段可以做到,比如一个View将自己处理的事件通过onTouchEvent强行交给其他View处理
  • 3、某个View一旦决定拦截,那么这个时间序列都只能由他来处理(如果时间序列能够传递给他的话)并且它的onInterceptTouchEvent不会再被调用。这条也很好理解,就是说当前View决定拦截一个事件后,那么系统会把同一个时间序列内的其他方法都直接交给她来处理,因此就不用再调用这个View的onInterceptTouchEvent去询问他是否需要拦截了
  • 4、某个View一旦开始处理事件,如果她不消耗ACTION_DOWN事件(onTouchEvent返回了false),那么同一个事件序列中的其他事件都不会再交给他处理,并且事件将重新交给它的父元素去处理,也就是父元素的onTouchEvent事件会被调用,意思就是说,一个事件序列一旦交给他,他就必须消耗掉,否则一个序列的剩下的事件都不会交给他,就好比说,领导交给你一件事,你没有做好,领导就不会在短期内再给你任务了。一个道理
  • 5、如果View不消耗ACTION_DOWN**事件以外的事件,那么这个点击事件就会消失,此时父控件的onTouchEvent不会被调用**,并且当前View会接受到后续的事件,最终这些消失的点击事件会交给Activity去处理。
  • 6、ViewGroup默认不拦截任何事件
  • 7、View没有onInterceptTouchEvent方法,一旦又点击事件传递给它,那么他的onTouchEvent方法就会被调用。
  • 8、View的onTouchEvent默认都会消耗掉事件(默认返回true),除非他是不可点击的
  • 9、View的enable属性不影响onTouchEvent的默认返回值。哪怕一个View是disable状态的,只要他的clickable或者longClickable有一个为true,那么他的onTouchEvent就返回true。
  • 10、OnClick会发生的前提是当前View**是可点击**的,并且他收到了down和up事件。
  • 11、事件传递的过程是由内向外的,挤时间总是县传递给父元素,然后再由父元素分发给子View,通过requestDisallowInterceptTouchEvent方法可以在子中干预父元素的的事件分发过程,但是ACTION_DOWN时间除外。

上面就是最事件分发的规则的一个总结,到这里事件分发的规则基本就说完了,事件分发是重点中的难点,所以大姐一定要多看几遍,多理解理解,只有这样才能更好的掌握它,掌握了事件分发,我们才能在写自定义控件上面游刃有余。
好了事件分发的规则就说到这里,下次我会通过源码来给大家具体讲解事件分发。

如果大家喜欢我的文章,请给与支持,转载请出名出处,请尊重每个人的劳动成果

0 0