分享

Android中触摸事件传递分发机制

 gearss 2016-04-15

触摸事件用MotionEvent表示,在Android中,一个触摸事件从产生到最终起作用,是一个很复杂的过程,但思路还是很清晰的,就是一层一层的传递,通过一个boolean值判断是否拦截或者消耗(也就是使用掉这个事件)。下面从基础的事件产生过程开始梳理整个流程:

事件的类型:

一般使用手机,在屏幕上的操作就是点击或滑动,所以一般触摸事件分为两类:

  • 点击事件:ACTION_DOWN–>ACTION_UP
  • 滑动事件:ACTION_DOWN–>ACTION_MOVE–>ACTION_MOVE … … –>ACTION_UP

可以看到,事件的开始都是ACTION_DOWN,结束是ACTION_UP。滑动事件相比点击事件,多了n个ACTION_MOVE事件,也就是滑动过程中手指与屏幕的交互,其他就没什么区别了。

事件的传递过程:

在Android中,Activity作为界面显示的基础,通常用来接收触摸事件,然后分发给界面中的视图控件。当一个触摸事件产生时,最先传递给当前Activity,然后由Activity内部的Window将事件传递给DecorView(也就是当前屏幕显示的界面的底层容器)接下来就是在开发者编写的ViewGroup和View中传递了,所以整理下事件传递过程如下图:
这里写图片描述

从图中可以看到,由于DecorView继承自FrameLayout,所以它是一个ViewGroup,ContentView也是一个ViewGroup,因此,整个传递过程可以简化为三个步骤:

Activity—->ViewGroup…—->View

也就是从Activity传递到ViewGroup,再经过n步的ViewGroup之间传递,最终传递给View。

事件传递的代码实现:

将以上传递规则通过代码实现,主要涉及到以下三个方法:

  • dispatchTouchEvent():分发触摸事件,默认返回super.dispatchTouchEvent(ev),事件向上分发。(一般,在这个方法中会有命中测试,也就是判断点击的坐标在当前viewGroup的哪个子布局中,然后将事件分发给对应的子布局)

  • onInterceptTouchEvent():拦截触摸事件,默认返回false,表示不拦截事件

  • onTouchEvent():处理触摸事件,默认返回false,表示不消耗事件

在Activity中存在两个回调方法:

public boolean dispatchTouchEvent(MotionEvent ev);    
public boolean onTouchEvent(MotionEvent ev); 
  • 1
  • 2

在ViewGroup中存在三个回调方法:

public boolean dispatchTouchEvent(MotionEvent ev);    
public boolean onInterceptTouchEvent(MotionEvent ev);    
public boolean onTouchEvent(MotionEvent ev);  
  • 1
  • 2
  • 3

在View中存在两个回调方法:

public boolean dispatchTouchEvent(MotionEvent ev);    
public boolean onTouchEvent(MotionEvent ev); 
  • 1
  • 2

可以看到,以上三个方法的返回值类型都是boolean类型,正如前面所说,在事件的传递过程中,通过boolean值判断是否拦截或者消耗,因此,有必要搞明白这三个方法的不同返回值的意义。

接下来通过测试代码加图解的方式来说明这三个方法的工作流程以及一些返回值的意义

点击View时的事件传递

一个自定义的ViewGroup,里面有一个自定义View,都是通过重写上述三个方法,用logcat跟踪事件流向,整个界面布局中只有这一个ViewGroup和其中的view,在MaintActivity中给他们都设置了onTouchListener,代码很简单,所以就不贴出来了。

下面是当View的onTouch返回false时,运行的logcat:

这里写图片描述

然后是根据运行情况,画的一个简单的流程图:

这里写图片描述

接下来是当View的onTouch返回true时,运行的logcat:

这里写图片描述

然后是流程图:

这里写图片描述

通过以上对比可以得出结论:

  • view的onTouchEvent返回值为false时,这个事件会往底层传由其父ViewGroup的onTouchEvent处理,直到某一层父ViewGroup的onTouchEvent返回true,如果传到顶层view依然返回false,则这个事件会消失,后续的事件序列也不会再被传递

  • view的onTouchEvent返回值为true,则这个view消耗此事件,后续事件序列也将交给这个view处理

以上,关于View的触摸事件传递,就先分析到这里

参考资料:
http://blog.csdn.net/xyz_lmn/article/details/12517911

http://www./thread-319301-1-1.html

http://blog.csdn.net/qiushuiqifei/article/details/9918527

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多