Android查缺补漏(View篇)--事件分发机制

事件分发机制是Android中非常重要的一个知识点,同时也是难点,相信到目前为止很多Android开发者对事件分发机制并没有一个非常系统的认识,当然也包括博主个人在内。可能在平时的开发工作中我们并没有意识到事件分发机制起到的作用,其实它是时刻存在的只是我们不知道而已,就像一些滑动冲突、点击事件之间的冲突等等大多是因为事件分发处理不当导致的。想起了博主大学时做过一个小项目,里面就出现了滑动冲突的问题,虽然最后在网上一步步看着别人的教程也糊里糊涂的解决了,但终究不知其所以然,那么今天就让我们一起来深入的探索一下事件分发机制吧。

什么是事件分发机制?

说了半天的事件分发机制那到底是个啥东西呢?我们不要把它想象的那么高深莫测,不要在心理上给自己设上障碍,其实很容易理解,博主的理解是:简单来说,事件分发机制就是Android系统对事件传递过程规定的一种事件传递规则,事件都会按照这个规则进行分发传递。

在研究事件分发机制之前,我们先来确定一下分析的步骤,化整为零,各个击破:

弄清楚分析目标:MotionEvent。

了解三个方法:dispatchTouchEvent(MotionEvent event)、onInterceptTouchEvent(Motion event)、onTouchEvent(MotionEvent event)。

MotionEvent事件的传递过程

小结

MotionEvent

其实点击事件的分发过程就是对MotionEvent事件的分发过程,当用户点击操作按下后,MotionEvent事件随即产生并通过一定的规则传递到指定的View上,这个传递的过程和规则就是事件分发机制。

而点击操作触发MotionEvent事件是一个事件流或者说是一个事件序列,其典型的事件类型有如下三种:

MotionEvent.ACTION_DOWN:手指刚点下屏幕时触发此类型。

MotionEvent.ACTION_MOVE:手指在屏幕上移动时会多次触发此类型。

MotionEvent.ACTION_UP:手指在屏幕上抬起时触发此类型。

要特别注意的是,通常情况下一个MotionEvent事件序列包含一个 ACTION_DOWN 若干个 ACTION_MOVE 和 ACTION_UP 是一个完整的事件序列。(点下去立马抬起手指时,会只有 ACTION_DOWN 和 ACTION_UP,这也是一个完整的事件序列)

dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent

boolean dispatchTouchEvent (MotionEvent event):

分发事件,只要事件能传递到当前View就一定会调用此方法,其返回值是一个布尔类型表示是否消耗事件。返回true代表消耗事件,事件流的后续部分还会接着传递过来;返回false代表不消耗事件,事件流的后续部分就不再传递于此。

boolean onInterceptTouchEvent (MotionEvent ev):

此方法表示是否拦截MotionEvent事件,只有ViewGroup类型的控件才有此方法。如果此方法返回true表示拦截事件,事件将传递给当前View的onTouchEvent()方法,而不再向其下级的View传递。如果此方法返回false表示不拦截事件,事件将传递给下级View的dispatchTouchEvent()。

boolean onTouchEvent (MotionEvent event):

此方法用来处理MotionEvent,返回值表示是否消耗事件。返回true表示消耗事件,那么事件流的后续部分还会传递过来;返回false表示不消耗事件,事件将交给上级View的onTouchEvent()处理,如果上级View的onTouchEvent()仍然返回false,那么事件将再交给上级的上级处理,以此类推,如果各级View的onTouchEvent()都不消耗事件,那么事件最终将交给Activity的onTouchEvent()处理。

上文说了这么多还是不够具体,先用流程图大体说明一个以上三个方法的关系,及调用流程,下文还会结合具体示例详细说明在事件分发传递中各个方法的调用规则。

三者关系大体如下图:

Android查缺补漏(View篇)--事件分发机制

MotionEvent事件传递过程

当手指点击屏幕产生一个Touch事件后,事件按照Activity->Window->View的顺序依次传递。

首先会传递给Activity的dispatchTouchEvent(),在此方法内部会将由Window处理,接着事件会传递给根View,根View接收到事件后就会按照事件分发机制去处理事件。

根View在这里就是一个ViewGroup,它在接受到事件后会调用dispatchTouchEvent(),在此方法内部会通过onInterceptTouchEvent()方法判断是否拦截事件,如果onInterceptTouchEvent()返回true就表示它要拦截事件,事件将传递给当前ViewGroup的onTouchEvent()。如果onInterceptTouchEvent()放回false就表示它不拦截事件,事件将传给其下级的View,调用下级View的dispatchTouchEvent()。

根View的下级View可能又是一个ViewGroup,如果这样的话其传递流程同根View一样。无论根View的下级View是不是ViewGroup,如果不拦截事件,最终事件会传递到一个纯View的控件上。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zywfff.html