前段时间刚接触过android手机开发。对它的事件传播机制不是非常了解,尽管网上也查了相关的资料,可是总认为理解模模糊糊,似是而非,于是自己就写个小demo測试了一下。

总算搞明确了它的详细机制。写下自己的结论。分享之,希望对初学android的人有所帮助

布局效果如图所看到的:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2h1bnFpdXdlaQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />

图1

參照上图先说说详细得到的结论:

1) onInterceptTouchEvent负责对touch事件进行拦截。对于嵌套的view最先运行的是事件拦截方法的是最外层的那个view的onInterceptTouchEvent方法,然后依次运行子视图的onInterceptTouchEvent,然后在运行子视图的子视图的事件拦截方法(当然在这里假设全部嵌套视图的onInterceptTouchEvent都会得到运行,让每一个视图的onInterceptTouchEvent返回false就可以)。參照上图,所以onInterceptTouchEvent运行顺序就是A--->B--->C--->D.也就是由父视图到子视图传递。

总之。事件拦截机制是由父视图開始发起对事件的拦截(出事了老子先上,儿子稍后)。

參照上图当手指触摸事件时。父视图A首先发起对该起事件的拦截。假设A拦截失败,就交给它的子视图B进行拦截;假设B拦截失败就交给B的子视图C再进行拦截..直到某一子视图对该次事件拦截成功。

2)某一视图拦截事件成功与否的推断标识是onInterceptTouchEvent方法的返回值,当返回true的时候说明拦截成功。返回false的时候说明当前视图对事件拦截失败。

3)以下说说拦截成功的情况,假设C视图对当前touch事件拦截成功。拦截成功意味着此次事件不会再传递到D视图了。

所以此时的D视图的onInterceptTouchEvent就得不到运行(事件没法到达了,还拦截谁呢?)。事件拦截成功后。紧接着就会对事件进行处理,处理的方法教给onTouchEvent方法处理。此时C视图拦截成功,那么紧接着就会运行C视图的onTouchEvent方法,这是不是就意味着当前touch事件是由C视图的onTouchEvent方法来处理的呢?这要由C视图的onTouchEvent方法的返回值来决定。当C视图的onTouchEvent返回true的时候,当前事件就由C全权处理,处理的当然是事件的各种action,什么MotionEvent.ACTION_MOVE,ACTION_UP都交给了C的onTouchEvent方法进行处理。所以此时就能够在C的onTouchEvent方法中进行switch(event.getAction)推断运行相关逻辑了。

假设返回的false,说明C视图对此事件不做处理或者处理不了,怎么办呢?儿子不行老爸来,于是事件就交到了B视图的onTouchEvent方法中。相同B对此事件处理与否还是看B的onTouchEvent返回值。详细的解释就跟C一样了,不复多言。

4)在A B C D的onInterceptTouchEvent和onTouchEvent都返回false的情况下。方法运行的顺序依次为A.onInterceptTouchEvent-->B.onInterceptTouchEvent-->C.onInterceptTouchEvent-->D.touchEvent(最深的子视图没重写onInterceptTouchEvent)-->C.touchEvent-->B.touchEvent-->A.touchEvent.也就是说拦截事件是父视图优先有子视图进行拦截,处理事件是子视图优先父视图进行处理。

总结:onInterceptTouchEvent负责对事件进行拦截,拦截成功后交给最先遇到onTouchEvent返回true的那个view进行处理。

结合事件源代码分析事件处理机制的话,能够阅读《从源代码角度解析android事件原理

以下将要详细解说上面结论是怎么得出的,准备分两部分进行一步步解说。假设上面说的看明确的话,以下的内容就不要看了,因为会非常啰嗦。

图1的布局代码例如以下所看到的:

  1. <com.example.demo.AView xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent" >
  5.  
  6. <com.example.demo.BView
  7. android:layout_width="match_parent"
  8. android:layout_height="match_parent" >
  9.  
  10. <com.example.demo.CView
  11. android:layout_width="match_parent"
  12. android:layout_height="match_parent" >
  13.  
  14. <com.example.demo.DView
  15. android:layout_width="match_parent"
  16. android:layout_height="match_parent"
  17. android:text="測试demo" />
  18. </com.example.demo.CView>
  19. </com.example.demo.BView>
  20.  
  21. </com.example.demo.AView>

当中最后一个D是一个自己定义的TextView。与A B C三个View的差别就是D仅仅重写了onTouchEvent方法。A B C 这三个自己定义控件还重写了onInterceptEvent方法。

D的代码例如以下,A B C代码基本上除了类名和输出log不一样外其余的都一样。所以为了降低这里仅仅贴出当中的一个。

DView的代码:

  1. public class DView extends TextView{
  2. private static String tag = "D";
  3. public DView(Context context, AttributeSet attrs, int defStyle) {
  4. super(context, attrs, defStyle);
  5. }
  6.  
  7. public DView(Context context, AttributeSet attrs) {
  8. super(context, attrs);
  9. }
  10.  
  11. public DView(Context context) {
  12. super(context);
  13. }
  14.  
  15. @Override
  16. public boolean onTouchEvent(MotionEvent event) {
  17. Log.e(tag, "--onTouchEvent--D");
  18. return false;
  19. }
  20. }

AView的代码和C D的总体几乎相同,就贴出来一个:

  1. public class AView extends RelativeLayout{
  2. private static String tag = "A";
  3. public AView(Context context) {
  4. super(context);
  5. }
  6.  
  7. public AView(Context context, AttributeSet attrs, int defStyle) {
  8. super(context, attrs, defStyle);
  9. }
  10.  
  11. public AView(Context context, AttributeSet attrs) {
  12. super(context, attrs);
  13. }
  14.  
  15. @Override
  16. public boolean onInterceptTouchEvent(MotionEvent ev) {
  17. Log.e(tag,"--onInterceptTouchEvent--A");
  18. return false;
  19. }
  20.  
  21. @Override
  22. public boolean onTouchEvent(MotionEvent event) {
  23. Log.e(tag,"--onTouchEvent---A" );
  24. return false;
  25. }
  26. }

刚開始的时候重写的方法全部返回false运行点击的效果输出log为:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2h1bnFpdXdlaQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" />

转换成效果图为:

从此图能够看出,onInterceptTouchEvent事件的运行顺序是由父控件到子控件。而且优先于自己控件的onTouchEvent方法运行,onTouchEvent事件运行的顺序正好相反由子控件到父控件。注意因为此时都返回了false,是没有哪一个view来处理此次的touch事件的各个ACTION的,这也是为什么onTouchEvent为什么会一直传递到A的原因。所以ACTION_MOVE和ACTION_UP等事件得不到对应(处理),此种情况下即使你在D的onTouchEvent方法里面写了例如以下代码,也不会得到运行。

  1. if(event.getAction()==MotionEvent.ACTION_MOVE){
  2. Log.e(tag, "--onTouchEvent--*****");
  3. }

1)假设A的InterceptTouchEvent返回了true,其余的仍然返回false,那么运行输出的log为:

转换成效果图为:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2h1bnFpdXdlaQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" />

能够发现此时A拦截了此次Touch事件。事件不再向A的子控件B C D传递。此时全部的action事件比方手指移动事件ACTION_MOVE或者ACTION_UP事件啦等等事件都交给A的onTouchEvent方法去处理(当然这是在onTouchEvent方法返回true的情况下,假设返回false经过測试时不会对应这些action的)。B,C ,D控件是的事件处理拦截方法和事件处理方法是无法得到运行的。

2)仅仅有B的onIntercepteTouchEvent事件返回了true的情况下,打印的log为

转换成效果图为:

此时由B拦截了此次Touch事件,并不会向C D子控件传递;相同的因为onTouchEvent事件返回为false,所以此次事件的event.getAction()的各种action都不会得到处理。

4)同理可知,C控件的onIntercept方法返回了true的情况下。其余的仍然返回false的情况下,输出log为

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2h1bnFpdXdlaQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" />

转换成效果图为

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2h1bnFpdXdlaQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" />

以下说说各个view的onTouchEvent返回true的情况

因为onTouchEvent事件是从子控件到父控件传递的。当D的onTouchEvent返回true的时候,经測试输出效果例如以下

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2h1bnFpdXdlaQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" />

转换成效果图为:

经过測试发现。此时D处理了此次Touch事件的各种action,C B D是的onTouchEvent的没有得到运行。

同理当C的onTouchEvent方法返回了true的时候,输出的log例如以下

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2h1bnFpdXdlaQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" />

转换成效果图例如以下:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2h1bnFpdXdlaQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" />

经过測试发现,其余情况一次类推,就不在啰嗦了。经过一步步的測试得出了文章开头的结文章有点啰嗦,希望能够对阅读此文的人有所帮助。

结合事件源代码分析事件处理机制的话,能够阅读《从源代码角度解析android事件原理

android事件拦截处理机制具体解释的更多相关文章

  1. android事件拦截处理机制详解

    前段时间刚接触过Android手机开发,对它的事件传播机制不是很了解,虽然网上也查了相关的资料,但是总觉得理解模模糊糊,似是而非,于是自己就写个小demo测试了一下.总算搞明白了它的具体机制.写下自己 ...

  2. Android 事件拦截机制一种粗鄙的解释

    对于Android事件拦截机制,相信对于大多数Android初学者是一个抓耳挠腮难于理解的问题.其实理解这个问题并不困难. 首先,你的明白事件拦截机制到底是怎么一回事?这里说的事件拦截机制,指的是对触 ...

  3. 讲讲Android事件拦截机制

    简介 什么是触摸事件?顾名思义,触摸事件就是捕获触摸屏幕后产生的事件.当点击一个按钮时,通常会产生两个或者三个事件--按钮按下,这是事件一,如果滑动几下,这是事件二,当手抬起,这是事件三.所以在And ...

  4. Android事件拦截机制简单分析

    前一阶段,在学习的时候,遇到了我觉得的我接触安卓以来的最多的一次事件拦截出来,那个项目,用到了slidemenu側滑菜单条,然后加上tab标签,还有轮播广告,listview上下滑动.viewpage ...

  5. Android事件的分发机制

    在分析Android事件分发机制前,明确android的两大基础控件类型:View和ViewGroup.View即普通的控件,没有子布局的,如Button.TextView. ViewGroup继承自 ...

  6. android 事件拦截 (Viewpager不可以左右滑动)

    以前没有做过真正的需求,所以从来没有觉得事件拦截分发处理有什么好懂的. 现在做需求了,真的是什么需求都有,你作为开发都要去研究实现.比如说,只能点不能滑动的viewpager.其实这都可以不用view ...

  7. Android事件拦截机制 - 两句话

    模拟情形:ViewGroupA ->ViewGroupB->View False往下走,True就停下.(适用于事件传递和事件处理)

  8. Android事件分发回传机制

    转载本博客,请注明出处:点击打开链接   http://blog.csdn.net/qq_32059827/article/details/52489026 之前以一个爷爷给孙子分馒头的故事,初探了安 ...

  9. Android事件分发机制完全解析,带你从源码的角度彻底理解

    Android事件构成 在Android中,事件主要包括点按.长按.拖拽.滑动等,点按又包括单击和双击,另外还包括单指操作和多指操作.所有这些都构成了Android中的事件响应.总的来说,所有的事件都 ...

随机推荐

  1. CRC(16位)多项式为 X16+X15+X2+1

    其对应校验二进制位列为1 1000 0000 0000 0101,可这有17位啊,我怎么和16位信息进行异或啊?是不是不要最高位的1 你没有弄明白crc的意思.这17位后面再添上16个零,然后开始抑或 ...

  2. 查看linux内核版本及操作系统版本的命令

    一.查看内核版本命令: (1)[root@localhost ~]#cat/proc/version Linux version 2.6.18-238.el5 (mockbuild@x86-012.b ...

  3. cocurrent包countdownlatch 倒计时门栓

    latch 英[lætʃ]美[lætʃ]n. 门闩; 弹簧锁; 锁是每个类的成员变量,它是这个类的固有属性,当然要声明为成员变量. 成员变量的初始化是通过对象的构造函数的. 锁是每个类的成员变量,它是 ...

  4. C# Json格式字符串

    转自:http://www.cnblogs.com/unintersky/p/3884712.html 将Json字符串转化成格式化表示的方法: 字符串反序列化为对象-->对象再序列化为字符串 ...

  5. hdu5884 Sort

    //--------------------------------------------------------------- /*---贪心策略+二分+队列 -----将原数组排序,然后每次取k ...

  6. tomcat下载安装以及在eclipse中的配置

    eclipse的下载地址是http://www.eclipse.org/downloads/. tomcat的下载地址为http://tomcat.apache.org/ 这两个工具的安装都非常eas ...

  7. 【OpenGL4.0】GLSL渲染语言入门与VBO、VAO使用:绘制一个三角形 【转】

    http://blog.csdn.net/xiajun07061225/article/details/7628146 以前都是用Cg的,现在改用GLSL,又要重新学,不过两种语言很多都是相通的. 下 ...

  8. OpenGL.Vertex Array Object (VAO) 【转】

    http://www.cppblog.com/init/archive/2012/02/21/166098.html 一 OpenGL抛弃glEnable(),glColor(),glVertex() ...

  9. tensorflow BasicRNNCell调试

    运行以下代码,进入~/anaconda3/lib/python3.5/site-packages/tensorflow/python/ops/rnn.py和~/anaconda3/lib/python ...

  10. MIT算法导论笔记

    详细MIT算法导论笔记 (网络链接) 第一讲:课程简介及算法分析 (Sheridan) 第二讲:渐近符号.递归及解法  (Sheridan) 第三讲:分治法(1)(Sheridan) 第四讲:快排及随 ...