android触碰消息传递机制

用户的每次触碰(onClick,onLongClick,onScroll,etc.)都是由一个ACTION_DOWN+n个ACTION_MOVE+1个ACTION_UP组成的,用户触碰必先有个ACTION_DOWN响应,用户触碰结束必然会有个ACTION_UP。(当然如果在途中被拦截,就可能不会有了!)那么View是如何分发消息和拦截消息呢?

1.View及其子类都会有的两个方法:

public boolean dispatchTouchEvent(MotionEvent ev) 这个方法用来分发TouchEvent
public boolean onTouchEvent(MotionEvent ev) 这个方法用来处理TouchEvent
2.特殊的View子类ViewGroup则还有一个方法:

public boolean onInterceptTouchEvent(MotionEvent ev) 这个方法用来拦截TouchEvent
3.分发

dispatchTouchEvent 收到触碰,则向最外层的View传递消息,再向子层的View分发
4.拦截:

onInterceptTouchEvent 拦截返回true表示要拦截消息,不要再向子View传递(这里的子View不是继承关系,而是包容关系)。返回false则表示不拦截消息,可以继续向下一层级的View传递消息,子View将可以dispatchTouchEvent 收到触碰消息再分发消息

5.消息处理:

onTouchEvent 处理事件,拦截了消息,或者是最后一个收到消息的View调用此方法来处理事件,若返回true,则表示正确接收并处理。若返回false则表示没有被处理,将向父View传递(这里的父View不是继承关系,而是包容关系)

Android事件模型之interceptTouchEvnet ,onTouchEvent关系正解

参考文档:

http://blog.csdn.net/liutao5757124/article/details/6097125

首先,看Android的官方文档正解

onInterceptTouchEvent()与onTouchEvent()的机制:

  1. down事件首先会传递到onInterceptTouchEvent()方法

  2. 如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return false,

  那么后续的move, up等事件将继续会先传递给该ViewGroup,之后才和down事件一样传递给最

  终的目标view的onTouchEvent()处理

  3. 如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return true,

  那么后续的move, up等事件将不再传递给onInterceptTouchEvent(),而是和down事件一样

  传递给该ViewGroup的onTouchEvent()处理,注意,目标view将接收不到任何事件。

  4. 如果最终需要处理事件的view的onTouchEvent()返回了false,那么该事件将被传递至其上一

  层次的view的onTouchEvent()处理

  5. 如果最终需要处理事件的view 的onTouchEvent()返回了true,那么后续事件将可以继续传递

  给该view的onTouchEvent()处理

这是官方文档的说法,要是自己没亲自去写个程序观察哈,基本上没法理解,所以上程序先,然后分析:

布局文件main.xml

Java代码

  1. <com.hao.layoutview1 abp="134" xmlns:android="http://schemas.android.com/apk/res/android"
  2. android:orientation="vertical" android:layout_width="fill_parent"
  3. android:layout_height="fill_parent">
  4. <com.hao.layoutview2 abp="137"
  5. android:orientation="vertical" android:layout_width="fill_parent"
  6. android:layout_height="fill_parent" android:gravity="center">
  7. <com.hao.mytextview abp="140"
  8. android:layout_width="wrap_content" android:layout_height="wrap_content"
  9. android:id="@+id/tv" android:text="AB" android:textSize="40sp"
  10. android:textStyle="bold" android:background="#FFFFFF"
  11. android:textColor="#0000FF" />
  12. 第一层自定义布局LayoutView1.java

    Java代码

    1. package com.hao;
    2. import android.content.Context;
    3. import android.util.AttributeSet;
    4. import android.util.Log;
    5. import android.view.MotionEvent;
    6. import android.widget.LinearLayout;
    7. public class LayoutView1 extends LinearLayout {
    8. private final String TAG = "LayoutView1";
    9. public LayoutView1(Context context, AttributeSet attrs) {
    10. super(context, attrs);
    11. Log.e(TAG,TAG);
    12. }
    13. @Override
    14. public boolean onInterceptTouchEvent(MotionEvent ev) {
    15. int action = ev.getAction();
    16. switch(action){
    17. case MotionEvent.ACTION_DOWN:
    18. Log.e(TAG,"onInterceptTouchEvent action:ACTION_DOWN");
    19. // return true; 在这就拦截了,后面的就不会得到事件
    20. break;
    21. case MotionEvent.ACTION_MOVE:
    22. Log.e(TAG,"onInterceptTouchEvent action:ACTION_MOVE");
    23. break;
    24. case MotionEvent.ACTION_UP:
    25. Log.e(TAG,"onInterceptTouchEvent action:ACTION_UP");
    26. break;
    27. case MotionEvent.ACTION_CANCEL:
    28. Log.e(TAG,"onInterceptTouchEvent action:ACTION_CANCEL");
    29. break;
    30. }
    31. return false;
    32. }
    33. @Override
    34. public boolean onTouchEvent(MotionEvent ev) {
    35. int action = ev.getAction();
    36. switch(action){
    37. case MotionEvent.ACTION_DOWN:
    38. Log.e(TAG,"onTouchEvent action:ACTION_DOWN");
    39. break;
    40. case MotionEvent.ACTION_MOVE:
    41. Log.e(TAG,"onTouchEvent action:ACTION_MOVE");
    42. break;
    43. case MotionEvent.ACTION_UP:
    44. Log.e(TAG,"onTouchEvent action:ACTION_UP");
    45. break;
    46. case MotionEvent.ACTION_CANCEL:
    47. Log.e(TAG,"onTouchEvent action:ACTION_CANCEL");
    48. break;
    49. }
    50. return true;
    51. // return false;
    52. }
    53. @Override
    54. protected void onLayout(boolean changed, int l, int t, int r, int b) {
    55. // TODO Auto-generated method stub
    56. super.onLayout(changed, l, t, r, b);
    57. }
    58. @Override
    59. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    60. // TODO Auto-generated method stub
    61. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    62. }
    63. }

      第二层布局LayoutView2.java

      Java代码

      1. package com.hao;
      2. import android.content.Context;
      3. import android.util.AttributeSet;
      4. import android.util.Log;
      5. import android.view.MotionEvent;
      6. import android.widget.LinearLayout;
      7. public class LayoutView2 extends LinearLayout {
      8. private final String TAG = "LayoutView2";
      9. public LayoutView2(Context context, AttributeSet attrs) {
      10. super(context, attrs);
      11. Log.e(TAG,TAG);
      12. }
      13. @Override
      14. public boolean onInterceptTouchEvent(MotionEvent ev) {
      15. int action = ev.getAction();
      16. switch(action){
      17. case MotionEvent.ACTION_DOWN:
      18. Log.e(TAG,"onInterceptTouchEvent action:ACTION_DOWN");
      19. // return true;
      20. break;
      21. case MotionEvent.ACTION_MOVE:
      22. Log.e(TAG,"onInterceptTouchEvent action:ACTION_MOVE");
      23. break;
      24. case MotionEvent.ACTION_UP:
      25. Log.e(TAG,"onInterceptTouchEvent action:ACTION_UP");
      26. break;
      27. case MotionEvent.ACTION_CANCEL:
      28. Log.e(TAG,"onInterceptTouchEvent action:ACTION_CANCEL");
      29. break;
      30. }
      31. return false;
      32. }
      33. @Override
      34. public boolean onTouchEvent(MotionEvent ev) {
      35. int action = ev.getAction();
      36. switch(action){
      37. case MotionEvent.ACTION_DOWN:
      38. Log.e(TAG,"onTouchEvent action:ACTION_DOWN");
      39. break;
      40. case MotionEvent.ACTION_MOVE:
      41. Log.e(TAG,"onTouchEvent action:ACTION_MOVE");
      42. break;
      43. case MotionEvent.ACTION_UP:
      44. Log.e(TAG,"onTouchEvent action:ACTION_UP");
      45. break;
      46. case MotionEvent.ACTION_CANCEL:
      47. Log.e(TAG,"onTouchEvent action:ACTION_CANCEL");
      48. break;
      49. }
      50. // return true;
      51. return false;
      52. }
      53. }
      54. 自定义MyTextView.java

        Java代码

        1. package com.hao;
        2. import android.content.Context;
        3. import android.util.AttributeSet;
        4. import android.util.Log;
        5. import android.view.MotionEvent;
        6. import android.view.View;
        7. import android.widget.TextView;
        8. public class MyTextView extends TextView {
        9. private final String TAG = "MyTextView";
        10. public MyTextView(Context context, AttributeSet attrs) {
        11. super(context, attrs);
        12. Log.e(TAG,TAG);
        13. }
        14. @Override
        15. public boolean onTouchEvent(MotionEvent ev) {
        16. int action = ev.getAction();
        17. switch(action){
        18. case MotionEvent.ACTION_DOWN:
        19. Log.e(TAG,"onTouchEvent action:ACTION_DOWN");
        20. break;
        21. case MotionEvent.ACTION_MOVE:
        22. Log.e(TAG,"onTouchEvent action:ACTION_MOVE");
        23. break;
        24. case MotionEvent.ACTION_UP:
        25. Log.e(TAG,"onTouchEvent action:ACTION_UP");
        26. break;
        27. case MotionEvent.ACTION_CANCEL:
        28. Log.e(TAG,"onTouchEvent action:ACTION_CANCEL");
        29. break;
        30. }
        31. return false;
        32. // return true;
        33. }
        34. public void onClick(View v) {
        35. Log.e(TAG, "onClick");
        36. }
        37. public boolean onLongClick(View v) {
        38. Log.e(TAG, "onLongClick");
        39. return false;
        40. }
        41. }
        42. 其实代码很简单,就是自定义了View,在View里面都重写了interceptTouchEvnet (),和onTouchEvent(),然后测试其返回值,对监听的影响,关键是自己动手,逐个测试,并预测结果,等你能预测结果的时候,也就懂了,需要修改的地方就是interceptTouchEvnet 和onTouchEvent的返回值,他们决定了事件监听的流程,下面我画了一张图,如有不足之处欢迎指正,谢谢!

          下面是我的正解:

          基本的规则是: *1.down事件首先会传递到onInterceptTouchEvent()方法 * * 2.如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return false(不拦截), * 那么后续的move, up等事件将继续会先传递给该ViewGroup,之后才和down事件一样传递给最终的目标view的onTouchEvent()处理。 * * 3.如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return true(拦截,那么后面的move,up事件不需要在看因为已经拦截了, 我们直接拿去处理onTouchEvent()就可以了),那么后续的move, up等事件将不再传递给onInterceptTouchEvent(), 而是和down事件一样传递给该ViewGroup的onTouchEvent()处理,注意,目标view将接收不到任何事件。 下面例子演示: * 1:LayoutView1(31375): onInterceptTouchEvent action:ACTION_DOWN * 2:LayoutView2(31375): onInterceptTouchEvent action:ACTION_DOWN * 3:LayoutView2(31375): onTouchEvent action:ACTION_DOWN * 4:LayoutView1(31375): onInterceptTouchEvent action:ACTION_MOVE * 5:LayoutView2(31375): onTouchEvent action:ACTION_MOVE * 6:LayoutView1(31375): onInterceptTouchEvent action:ACTION_MOVE * 7:LayoutView2(31375): onTouchEvent action:ACTION_MOVE * 8:LayoutView1(31375): onInterceptTouchEvent action:ACTION_UP * 9:LayoutView2(31375): onTouchEvent action:ACTION_UP * 该设置为: * onInterceptTouchEvent:LayoutView1为false,LayoutView2为true * onTouchEvent:LayoutView2为true * 故而事件在LayoutView2(onInterceptTouchEvent:返回true)时被拦截并处理,根据上面说法就是LayoutView2后续的MOVE,UP操作都不在经过onInterceptTouchEvent,直接 * 交给onTouchEvent处理,结果也的确如此。(见:LayoutView2的3,5,7,9,第一次是onInterceptTouchEvent处理如1,以后交给onTouchEvent) * 而LayoutView1都还是要经过onInterceptTouchEvent(见LayoutView1的4,6,8) * * 4.如果最终需要处理事件的view的onTouchEvent()返回了false(没能处理这个事件,不能丢在传回来让父继续), * 那么该事件将被传递至其上一层次的view的onTouchEvent()处理。 * ************************************************************************** * 感觉像是一个圈,然后一直在找一个能处理这个消息的人,如果找到了就结束,没找到就循环,直到回到发出消息的那个人 * 注(对下面):没有标注的DOWN表示拦截事件onInterceptTouchEvent,标注了onTouchEvent就是处理事件 * a.如果都没处理(onInterceptTouchEvent返回false): A(DOWN)-->B(DOWN)-->C(onTouchEvent DOWN)-->B(onTouchEvent DOWN)-->A(onTouchEvent DOWN),没有执行UP事件,注意有MOVE的话,在DOWN和UP之间,下面的都一样。 *b. B处理(B的onInterceptTouchEvent返回true): A(DOWN)-->B(DOWN)-->B(onTouchEvent)-->A(onTouchEvent UP)-->B(onTouchEvent UP)-->(over) * 形象说明:如果父亲不拦截消息就传给儿子,如果儿子要这个消息就处理(DOWN),结束,然后有父亲1--父亲2--儿子以此释放消息(UP)。 然是如果儿子对这个消息置之不理,那这个消息又传回父亲,由父亲来处理即。
          下面给出了5中情况(不拦截表示onInterceptTouchEvent返回false): * 11** 父亲1(LayoutView1不拦截false)---父亲2(LayoutView2不拦截false)--儿子(MyTextView,onTouchEvent return true)--结束 * 22** 父亲1(LayoutView1不拦截false)---父亲2(LayoutView2不拦截false)--儿子(MyTextView,onTouchEvent return false)--回传给父亲2(onTouchEvent return true)--结束 * 33** 父亲1(LayoutView1不拦截false)---父亲2(LayoutView2不拦截false)--儿子(MyTextView,onTouchEvent return false)--回传给父亲2(onTouchEvent return false)--父亲1(onTouchEvent return true)--结束(如果都没处理不在执行UP ACTION) * 44** 父亲1(LayoutView1拦截true)--父亲1(onTouchEvent return true)--结束 (DOWN--DOWN(onTouchEvent)--UP(onTouchEvent)) * 55** 父亲1(LayoutView1拦截false)--父亲2(LayoutView2拦截true)--父亲2(onTouchEvent return false)--父亲1(onTouchEvent return true)--结束 (DOWN1--DOWN2--DOWN(2 onTouchEvent)--DOWN(1 onTouchEvent)--UP(1 onTouchEvent))(1:父亲2,2:父亲2) * * *************************************************************************** * 5.如果最终需要处理事件的view 的onTouchEvent()返回了true,那么后续事件将可以继续传递给该view的onTouchEvent()处理。 */
          下面给出一张处理的流程图:

          下附源代码:

Android开发之触摸事件处理机制详解相关推荐

  1. android什么控件能够输入多行文字,Android开发:文本控件详解——EditText(一)基本属性...

    一.简单实例: EditText输入的文字样式部分的属性,基本都是和TextView中的属性一样. 除此之外,EditText还有自己独有的属性. 二.基本属性: hint 输入框显示的提示文本 te ...

  2. React Native 手势触摸事件机制详解(进阶篇)

    源码已开源到Github,详细代码可以查看:<React Native 触摸事件代码实践>. 在基础篇,对RN中的触摸事件做了详细的介绍.相信大家对于触摸事件流程机制有了更为清晰的认识.没 ...

  3. Android开发-CardView卡片View的详解,头条三面技术四面HR

    CardView一般用于需要显示阴影效果的UI,此外CardView还提供了圆角的功能.(嘿嘿,这东西还能直接设置成圆形,可以简单的弄成圆形View).CardView其实本身是使用FrameLayo ...

  4. Android 开发架构-MVC MVP MVVM详解

    何为架构 架构,即程序的逻辑组织结构,是指导开发过程中划分程序逻辑模块的关键,好的架构要使程序达到高内聚低耦合的设计目标.例如一个人,身体的骨骼即为身体的架构,有了基本骨架之后,才可以决定在头颅里开发 ...

  5. 线程对象Android 开发之多线程处理、Handler 详解

    发一下牢骚和主题无关: 每日一道理 毅力,是千里大堤一沙一石的凝聚,一点点地累积,才有前不见头后不见尾的壮丽:毅力,是春蚕吐丝一缕一缕的环绕,一丝丝地坚持,才有破茧而出重见光明的辉煌: 毅力,是远航的 ...

  6. Android 开发之多线程处理、Handler 详解

    Android开发过程中为什么要多线程 我们创建的Service.Activity以及Broadcast均是一个主线程处理,这里我们可以理解为UI线程.但是在操作一些耗时操作时,比如I/O读写的大文件 ...

  7. React Native 手势触摸事件机制详解(基础篇)

          欢迎大家关注[跨平台开发那些事]公众号,定期推送跨平台开发技术实践.        源码已开源到Github,详细代码可以查看:<React Native 触摸事件代码实践>. ...

  8. Android开发实现高德地图定位详解

     一. 要实现高德地图定位呢,首先需要做好以下几步准备: 1. 在高德开放平台注册帐号 注册地址:http://lbs.amap.com 2. 在开发中下载Android平台下的地图SDK和定位S ...

  9. Android开发笔记之:Log图文详解(Log.v,Log.d,Log.i,Log.w,Log.e)

    本篇文章是对Android中的Log进行了详细的分析介绍,需要的朋友参考下 在Android群里,经常会有人问我,Android Log是怎么用的,今天我就把从网上以及SDK里东拼西凑过来,让大家先一 ...

最新文章

  1. 时间序列(三)滑动窗口
  2. c++ 遍历多级目录
  3. 【量化投资】策略三(聚宽)
  4. 动手造轮子:实现一个简单的 EventBus
  5. mysql查看用户名_Mysql创建数据表的方法介绍(附示例)
  6. 618哪家空调最受欢迎?格力奥克斯互撕 友商却笑到最后
  7. 【经验】在CSS中定义超链接样式a:link、a:visited、a:hover、a:active的顺序
  8. 枚举类型和int以及string的相互转换
  9. c:递归算法的三个demo:八皇后问题、台阶问题、汉诺塔
  10. Silverlight 操作Excel 中的进程资源释放问题(续)
  11. 简易旋转倒立摆设计报告
  12. 前端特效——复杂下雪,雪花纷飞(纯css)
  13. 单反相机的一般入门设置建议
  14. 李白的诗: 南陵别儿童入京
  15. TCP协议全面实验分析详解
  16. uniapp 实现人脸认证
  17. 衡水中学的《凉凉》 警醒自己
  18. matlab 星座图 qam,16QAM_星形及矩形星座图调制解调MATLAB代码.doc
  19. unity+高通vuforia开发增强现实(AR)教程(一)
  20. 开源代码基于深度学习的超分辨率如何让大脑显微镜成像去除毛刺

热门文章

  1. Code Splitting 代码分离
  2. mariadb安装和使用
  3. BurpSuite日志分析过滤工具,加快SqlMap进行批量扫描的速度
  4. Poj 2887-Big String Splay
  5. MyBitis(iBitis)系列随笔之六:mybitis与spring集成
  6. Android -- EventBus使用
  7. @RenderBody、@RenderSection、@RenderPage、Html.RenderPartial、Html.RenderAction的作用和区别...
  8. Google 公司的 Java 语言编写规范
  9. 联合登陆【支付宝、网易、QQ】
  10. Nginx在mvvm模式中的使用