前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >进阶必备-Android事件分发机制

进阶必备-Android事件分发机制

作者头像
吴延宝
发布2018-10-18 15:14:27
8660
发布2018-10-18 15:14:27
举报

一、简介

或许你会问,“为什么我一定要知道View的事件分发机制?”。因为我们在实际开发的过程中,经常会遇到多层的View互相嵌套以后,对某一个View进行滑动的时候,特别不灵敏,甚至于没法滑动。这种滑动冲突的解决需要我们清楚的掌握View的事件分发机制。那下面我们详细的讲解下View的整个事件机制。 Android将View的事件封装到MotionEvent这个类中,这也是监听touch事件中回调给我们的参数public boolean onTouchEvent(MotionEvent event) 。通常事件我们主要关心下面几种类型:

  • MotionEvent.ACTION_DOWN 当我们手指按下屏幕的第一个事件便是ACTION_DOWN了,也就是意味着事件的开始。
  • MotionEvent.ACTION_MOVE 当我们手指按下屏幕后,在屏幕上滑动的过程,此事件就会不断的触发。
  • MotionEvent.ACTION_UP 此事件在我们手指从屏幕抬起的时候会触发。
  • MotionEvent.ACTION_CANCEL 这个事件说起来稍微复杂一点,举个栗子:当我们的外层View将事件传递给内层View去处理时,外层View的拦截方法一般会返回false,但是当某个条件触发后,外层View想自己处理接下来的事件,就拦截了事件分发,此时内层View就会收到ACTION_CANCEL的事件。
  • MotionEvent.ACTION_OUTSIDE 这个事件我们不常用到,考虑这种场景。我们又一个Diallog弹出,当我们按Dialog以外的屏幕将Dialog消失掉。这个时候可以考虑监听这个事件,要想使用这个事件我们必须对当前的Window设置一个Flag:FLAG_WATCH_OUTSIDE_TOUCH

下面我们介绍和事件分发相关的几个方法:

  • dispatchTouchEvent(MotionEvent event) 这个方法是用来处理向下分发事件逻辑的,我们通过观察ViewGrope源码中的代码知道,这个方法细节较多,检出我们比较关心的逻辑就是这个方法会先判断子View是否有调用disallowIntercept父View去拦截事件,如果没有,父View自己会调用onInterceptTouchEvent判断自己是否有拦截,如果拦截事件,将调用父View自己的onTouchEvent方法去处理事件,如果没有拦截事件,事件将继续分发到子View中处理。
  • onInterceptTouchEvent(MotionEvent event) 用来申明是否拦截事件继续向下分发,如果返回true,事件将不会继续向下分发,而是交由自己的onTouchEvent方法处理。
  • onTouchEvent(MotionEvent event) 显然,这个就是事件处理的方法了。
  • onTouch(MotionEvent event) 这个方法是在我们对某一个setOnTouchListener时回调,也就是在传递事件的时候,在交给View本身的onTouchEvent处理之前判断是否有监听的TouchListener,如果有优先调用TouchListener的onTouch方法处理。

二、详细分析View的分发事件

我们都知道,Android的View是树形结构的,所以当一个事件来临的时候一般是从根部分发下来的。为了方便我们接下来的理解,我们构建一个这样的例子:

假设我们有这样一个页面,最外层是一个ViewGroup A,里面嵌套着一个ViewGroup B,B里面有一个ViewGroup C。

情景1:

假设我们对事件不做任何拦截,也不做任何处理。当我们点击View C,这个时候我们看到的Log显示调用顺序为:

代码语言:javascript
复制
A -> dispatchTouchEvent
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 BonTouchEvent中返回true,再次点击事件并滑动,我们得到的Log如下:

代码语言:javascript
复制
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记录:

代码语言:javascript
复制
A -> dispatchTouchEvent
A -> onInterceptTouchEvent
B -> dispatchTouchEvent
B -> onInterceptTouchEvent
B -> onTouchEvent ACTION_DOWN
A -> onTouchEvent ACTION_DOWN

相比较于情景2,ACTION_DOWN事件不会下发到C,由于没有View表示能处理,所以后续的事件均被取消。

三、总结

通过我们实际运行和分析源码发现,我们ViewGroup事件的分发流程如下所示:

对着上图大家不妨尝试分析下:

  • 如果B的onInterceptTouchEvent中返回true并且onTouchEvent中返回true,那么Log又将是怎样的呢?

可以关注下方公众号,回复“666”获取答案哦~

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-10-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 南京Android部落 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、简介
  • 二、详细分析View的分发事件
    • 情景1:
      • 情景2:
        • 情景3:
        • 三、总结
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档