嗨,你终于来啦 ~ 等你很久啦~ 从今天开始天天分享一篇Android须要了解的知识点,喜欢的小伙伴欢迎关注,我会按期分享Android知识点及解析,还会不断更新的BATJ面试专题,欢迎你们前来探讨交流,若有好的文章也欢迎投稿。更新了两天Android基础小知识,今天咱们来说讲Android进阶必需要了解的事件分发机制。面试
或许你会问,“为何我必定要知道View的事件分发机制?”。由于咱们在实际开发的过程当中,常常会遇到多层的View互相嵌套之后,对某一个View进行滑动的时候,特别不灵敏,甚至于无法滑动。这种滑动冲突的解决须要咱们清楚的掌握View的事件分发机制。那下面咱们详细的讲解下View的整个事件机制。
Android将View的事件封装到MotionEvent这个类中,这也是监听touch事件中回调给咱们的参数 public boolean onTouchEvent(MotionEvent event) 。一般事件咱们主要关心下面几种类型:spa
当咱们手指按下屏幕的第一个事件即是ACTION_DOWN了,也就是意味着事件的开始。code
当咱们手指按下屏幕后,在屏幕上滑动的过程,此事件就会不断的触发。orm
此事件在咱们手指从屏幕抬起的时候会触发。cdn
这个事件提及来稍微复杂一点,举个栗子:当咱们的外层View将事件传递给内层View去处理时,外层View的拦截方法通常会返回false,可是当某个条件触发后,外层View想本身处理接下来的事件,就拦截了事件分发,此时内层View就会收到ACTION_CANCEL的事件。blog
这个事件咱们不经常使用到,考虑这种场景。咱们又一个Diallog弹出,当咱们按Dialog之外的屏幕将Dialog消失掉。这个时候能够考虑监听这个事件,要想使用这个事件咱们必须对当前的 Window 设置一个Flag: FLAG_WATCH_OUTSIDE_TOUCH 。事件
下面咱们介绍和事件分发相关的几个方法:开发
这个方法是用来处理向下分发事件逻辑的,咱们经过观察ViewGrope源码中的代码知道,这个方法细节较多,检出咱们比较关心的逻辑就是这个方法会先判断子View是否有调用disallowIntercept父View去拦截事件,若是没有,父View本身会调用onInterceptTouchEvent判断本身是否有拦截,若是拦截事件,将调用父View本身的onTouchEvent方法去处理事件,若是没有拦截事件,事件将继续分发到子View中处理。源码
用来申明是否拦截事件继续向下分发,若是返回true,事件将不会继续向下分发,而是交由本身的onTouchEvent方法处理。it
显然,这个就是事件处理的方法了。
这个方法是在咱们对某一个 setOnTouchListener 时回调,也就是在传递事件的时候,在交给View自己的onTouchEvent处理以前判断是否有监听的TouchListener,若是有优先调用TouchListener的onTouch方法处理。
咱们都知道,Android的View是树形结构的,因此当一个事件来临的时候通常是从根部分发下来的。为了方便咱们接下来的理解,咱们构建一个这样的例子:
假设咱们有这样一个页面,最外层是一个ViewGroup A,里面嵌套着一个ViewGroup B,B里面有一个ViewGroup C。情景1 :
假设咱们对事件不作任何拦截,也不作任何处理。当咱们点击View C,这个时候咱们看到的Log显示调用顺序为:
A -> onInterceptTouchEvent
B -> dispatchTouchEvent
B -> onInterceptTouchEvent
C -> dispatchTouchEvent
C -> onInterceptTouchEvent
C -> onTouchEvent ACTION_DOWN
B -> onTouchEvent ACTION_DOWN
A -> onTouchEvent ACTION_DOWN
复制代码
因为没有任何View处理事件,最终会回调到Activity的onTouchEvent中去处理。从这个情景中咱们能够知道,事件向下传递的过程以及处理事件的向上传递的过程。
情景2 :
假设咱们在View B的onTouchEvent中返回true,再次点击事件并滑动,咱们获得的Log以下:
A -> dispatchTouchEvent
A -> onInterceptTouchEvent
B -> dispatchTouchEvent
B -> onInterceptTouchEvent
C -> dispatchTouchEvent
C -> onInterceptTouchEvent
C -> onTouchEvent ACTION_DOWN
B -> onTouchEvent ACTION_DOWN
A -> dispatchTouchEvent
A -> onInterceptTouchEvent
B -> dispatchTouchEvent
B -> onTouchEvent ACTION_MOVE
A -> dispatchTouchEvent
A -> onInterceptTouchEvent
B -> dispatchTouchEvent
B -> onTouchEvent ACTION_UP
复制代码
咱们发现,除了ACTION_DOWN事件会下发到C,后续的事件不会再下发这是由于,当咱们发现某一层View的onTouchEvent返回true之后,会有一个标志位表示后续的事件都由此View处理,后续事件再也不下发到子View,直到 ACTION UP 事件后将标志位重置。
情景3* :
假设咱们在View B的onInterceptTouchEvent中返回true,再次点击C会怎么样呢?咱们获得以下的Log记录:
A -> dispatchTouchEvent
A -> onInterceptTouchEvent
B -> dispatchTouchEvent
B -> onInterceptTouchEvent
B -> onTouchEvent ACTION_DOWN
A -> onTouchEvent ACTION_DOWN
复制代码
相比较于情景2,ACTION_DOWN事件不会下发到C,因为没有View表示能处理,因此后续的事件均被取消。
经过咱们实际运行和分析源码发现,咱们ViewGroup事件的分发流程以下所示:
对着上图你们不妨尝试分析下:
知道的小伙伴们能够在下面评论回答哦~