Android中有各种各样的事件,以响应用户的操作。这些事件可以分为按键事件和触屏事件。而Touch事件是触屏事件的基础事件,在进行Android开发时经常会用到,所以非常有必要深入理解它的原理机制。

Android Touch事件原理描述

一个最简单的屏幕触摸动作触发了一系列Touch事件:ACTION_DOWN->ACTION_MOVE->ACTION_MOVE->ACTION_MOVE...->ACTION_MOVE->ACTION_UP。

当屏幕中包含一个ViewGroup,而这个ViewGroup又包含一个子view,这个时候android系统如何处理Touch事件呢?到底是ViewGroup来处理Touch事件,还是子view来处理Touch事件呢?我只能很肯定的对你说不一定。呵呵,为什么呢?看看下面我的调查结果你就明白了。

Android系统中的每个View的子类都具有下面三个和TouchEvent处理密切相关的方法:

1)public boolean dispatchTouchEvent(MotionEvent ev)  这个方法用来分发TouchEvent

2)public boolean onInterceptTouchEvent(MotionEvent ev) 这个方法用来拦截TouchEvent

3)public boolean onTouchEvent(MotionEvent ev) 这个方法用来处理TouchEvent

当TouchEvent发生时,首先Activity将TouchEvent传递给最顶层的View, TouchEvent最先到达最顶层 view 的 dispatchTouchEvent ,然后由  dispatchTouchEvent 方法进行分发,如果dispatchTouchEvent返回true ,则交给这个view的onTouchEvent处理,如果dispatchTouchEvent返回 false ,则交给这个 view 的 interceptTouchEvent 方法来决定是否要拦截这个事件,如果 interceptTouchEvent 返回 true ,也就是拦截掉了,则交给它的 onTouchEvent 来处理,如果 interceptTouchEvent 返回 false ,那么就传递给子 view ,由子 view 的 dispatchTouchEvent 再来开始这个事件的分发。如果事件传递到某一层的子 view 的 onTouchEvent 上了,这个方法返回了 false ,那么这个事件会从这个 view 往上传递,都是 onTouchEvent 来接收。而如果传递到最上面的 onTouchEvent 也返回 false 的话,这个事件就会“消失”,而且接收不到下一次事件。

Android Touch事件实例分析

通过语言描述这个处理逻辑很抽象,下面我就用代码来具体说明一下。

layout配置文件 main.xml:

XML/HTML代码
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <test.lzqdiy.MyLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:orientation="vertical"
  4. android:layout_width="fill_parent"
  5. android:layout_height="fill_parent"
  6. android:gravity="center" >
  7. <test.lzqdiy.MyTextView
  8. android:layout_width="200px"
  9. android:layout_height="200px"
  10. android:id="@+id/tv"
  11. android:text="lzqdiy"
  12. android:textSize="40sp"
  13. android:textStyle="bold"
  14. android:background="#FFFFFF"
  15. android:textColor="#0000FF"/>
  16. </test.lzqdiy.MyLinearLayout>

节点层次很简单,一个LinearLayout中添加了一个TextView。

下面是java代码:

Java代码
  1. package test.lzqdiy;
  2. import android.app.Activity;
  3. import android.os.Bundle;
  4. public class TestTouchEventApp extends Activity {
  5. /** Called when the activity is first created. */
  6. @Override
  7. public void onCreate(Bundle savedInstanceState) {
  8. super.onCreate(savedInstanceState);
  9. setContentView(R.layout.main);
  10. }
  11. }
  12. package test.lzqdiy;
  13. import android.content.Context;
  14. import android.util.AttributeSet;
  15. import android.util.Log;
  16. import android.view.MotionEvent;
  17. import android.widget.LinearLayout;
  18. public class MyLinearLayout extends LinearLayout {
  19. private final String TAG = "MyLinearLayout";
  20. public MyLinearLayout(Context context, AttributeSet attrs) {
  21. super(context, attrs);
  22. Log.d(TAG, TAG);
  23. }
  24. @Override
  25. public boolean dispatchTouchEvent(MotionEvent ev) {
  26. int action = ev.getAction();
  27. switch (action) {
  28. case MotionEvent.ACTION_DOWN:
  29. Log.d(TAG, "dispatchTouchEvent action:ACTION_DOWN");
  30. break;
  31. case MotionEvent.ACTION_MOVE:
  32. Log.d(TAG, "dispatchTouchEvent action:ACTION_MOVE");
  33. break;
  34. case MotionEvent.ACTION_UP:
  35. Log.d(TAG, "dispatchTouchEvent action:ACTION_UP");
  36. break;
  37. case MotionEvent.ACTION_CANCEL:
  38. Log.d(TAG, "dispatchTouchEvent action:ACTION_CANCEL");
  39. break;
  40. }
  41. return super.dispatchTouchEvent(ev);
  42. }
  43. @Override
  44. public boolean onInterceptTouchEvent(MotionEvent ev) {
  45. int action = ev.getAction();
  46. switch (action) {
  47. case MotionEvent.ACTION_DOWN:
  48. Log.d(TAG, "onInterceptTouchEvent action:ACTION_DOWN");
  49. break;
  50. case MotionEvent.ACTION_MOVE:
  51. Log.d(TAG, "onInterceptTouchEvent action:ACTION_MOVE");
  52. break;
  53. case MotionEvent.ACTION_UP:
  54. Log.d(TAG, "onInterceptTouchEvent action:ACTION_UP");
  55. break;
  56. case MotionEvent.ACTION_CANCEL:
  57. Log.d(TAG, "onInterceptTouchEvent action:ACTION_CANCEL");
  58. break;
  59. }
  60. return false;
  61. }
  62. @Override
  63. public boolean onTouchEvent(MotionEvent ev) {
  64. int action = ev.getAction();
  65. switch (action) {
  66. case MotionEvent.ACTION_DOWN:
  67. Log.d(TAG, "---onTouchEvent action:ACTION_DOWN");
  68. break;
  69. case MotionEvent.ACTION_MOVE:
  70. Log.d(TAG, "---onTouchEvent action:ACTION_MOVE");
  71. break;
  72. case MotionEvent.ACTION_UP:
  73. Log.d(TAG, "---onTouchEvent action:ACTION_UP");
  74. break;
  75. case MotionEvent.ACTION_CANCEL:
  76. Log.d(TAG, "---onTouchEvent action:ACTION_CANCEL");
  77. break;
  78. }
  79. return true;
  80. }
  81. }
  82. package test.lzqdiy;
  83. import android.content.Context;
  84. import android.util.AttributeSet;
  85. import android.util.Log;
  86. import android.view.MotionEvent;
  87. import android.widget.TextView;
  88. public class MyTextView extends TextView {
  89. private final String TAG = "MyTextView";
  90. public MyTextView(Context context, AttributeSet attrs) {
  91. super(context, attrs);
  92. }
  93. @Override
  94. public boolean dispatchTouchEvent(MotionEvent ev) {
  95. int action = ev.getAction();
  96. switch (action) {
  97. case MotionEvent.ACTION_DOWN:
  98. Log.d(TAG, "dispatchTouchEvent action:ACTION_DOWN");
  99. break;
  100. case MotionEvent.ACTION_MOVE:
  101. Log.d(TAG, "dispatchTouchEvent action:ACTION_MOVE");
  102. break;
  103. case MotionEvent.ACTION_UP:
  104. Log.d(TAG, "dispatchTouchEvent action:ACTION_UP");
  105. break;
  106. case MotionEvent.ACTION_CANCEL:
  107. Log.d(TAG, "onTouchEvent action:ACTION_CANCEL");
  108. break;
  109. }
  110. return super.dispatchTouchEvent(ev);
  111. }
  112. @Override
  113. public boolean onTouchEvent(MotionEvent ev) {
  114. int action = ev.getAction();
  115. switch (action) {
  116. case MotionEvent.ACTION_DOWN:
  117. Log.d(TAG, "---onTouchEvent action:ACTION_DOWN");
  118. break;
  119. case MotionEvent.ACTION_MOVE:
  120. Log.d(TAG, "---onTouchEvent action:ACTION_MOVE");
  121. break;
  122. case MotionEvent.ACTION_UP:
  123. Log.d(TAG, "---onTouchEvent action:ACTION_UP");
  124. break;
  125. case MotionEvent.ACTION_CANCEL:
  126. Log.d(TAG, "---onTouchEvent action:ACTION_CANCEL");
  127. break;
  128. }
  129. return true;
  130. }
  131. }

为了指代方便,下面将MyLinearLayout简称为L,将MyTextView简称为T,L.onInterceptTouchEvent=true 表示的含义为MyLinearLayout中的onInterceptTouchEvent方法返回值为true,通过程序运行时输出的Log来说明调用时序。

第1种情况 L.onInterceptTouchEvent=false&& L.onTouchEvent=true &&T.onTouchEvent=true 输出下面的Log:

D/MyLinearLayout(11865): dispatchTouchEvent action:ACTION_DOWN
D/MyLinearLayout(11865): onInterceptTouchEvent action:ACTION_DOWN
D/MyTextView(11865): dispatchTouchEvent action:ACTION_DOWN
D/MyTextView(11865): ---onTouchEvent action:ACTION_DOWN
D/MyLinearLayout(11865): dispatchTouchEvent action:ACTION_MOVE
D/MyLinearLayout(11865): onInterceptTouchEvent action:ACTION_MOVE
D/MyTextView(11865): dispatchTouchEvent action:ACTION_MOVE
D/MyTextView(11865): ---onTouchEvent action:ACTION_MOVE
...........省略其他的ACTION_MOVE事件Log
D/MyLinearLayout(11865): dispatchTouchEvent action:ACTION_UP
D/MyLinearLayout(11865): onInterceptTouchEvent action:ACTION_UP
D/MyTextView(11865): dispatchTouchEvent action:ACTION_UP
D/MyTextView(11865): ---onTouchEvent action:ACTION_UP

结论:TouchEvent完全由TextView处理。

第2种情况  L.onInterceptTouchEvent=false&& L.onTouchEvent=true &&T.onTouchEvent=false 输出下面的Log:

D/MyLinearLayout(13101): dispatchTouchEvent action:ACTION_DOWN
D/MyLinearLayout(13101): onInterceptTouchEvent action:ACTION_DOWN
D/MyTextView(13101): dispatchTouchEvent action:ACTION_DOWN
D/MyTextView(13101): ---onTouchEvent action:ACTION_DOWN
D/MyLinearLayout(13101): ---onTouchEvent action:ACTION_DOWN
D/MyLinearLayout(13101): dispatchTouchEvent action:ACTION_MOVE
D/MyLinearLayout(13101): ---onTouchEvent action:ACTION_MOVE
...........省略其他的ACTION_MOVE事件Log
D/MyLinearLayout(13101): dispatchTouchEvent action:ACTION_UP
D/MyLinearLayout(13101): ---onTouchEvent action:ACTION_UP

结论:TextView只处理了ACTION_DOWN事件,LinearLayout处理了所有的TouchEvent。

第3种情况  L.onInterceptTouchEvent=true&& L.onTouchEvent=true 输出下面的Log:

D/MyLinearLayout(13334): dispatchTouchEvent action:ACTION_DOWN
D/MyLinearLayout(13334): onInterceptTouchEvent action:ACTION_DOWN
D/MyLinearLayout(13334): ---onTouchEvent action:ACTION_DOWN
D/MyLinearLayout(13334): dispatchTouchEvent action:ACTION_MOVE
D/MyLinearLayout(13334): ---onTouchEvent action:ACTION_MOVE
...........省略其他的ACTION_MOVE事件Log
D/MyLinearLayout(13334): dispatchTouchEvent action:ACTION_UP
D/MyLinearLayout(13334): ---onTouchEvent action:ACTION_UP

结论:LinearLayout处理了所有的TouchEvent。

第4种情况  L.onInterceptTouchEvent=true&& L.onTouchEvent=false 输出下面的Log:

D/MyLinearLayout(13452): dispatchTouchEvent action:ACTION_DOWN
D/MyLinearLayout(13452): onInterceptTouchEvent action:ACTION_DOWN
D/MyLinearLayout(13452): ---onTouchEvent action:ACTION_DOWN

结论:LinearLayout只处理了ACTION_DOWN事件,那么其他的TouchEvent被谁处理了呢?答案是LinearLayout最外层的Activity处理了TouchEvent。

Android Touch事件原理加实例分析的更多相关文章

  1. React-Native系列Android——Touch事件原理及状态效果

    Native原生相比于Hybrid或H5最大长处是具有流畅和复杂的交互效果,触摸事件便是当中重要一项,包括点击(Click).长按(LongClick).手势(gesture)等. 以最简单常见的点击 ...

  2. Android Touch事件传递机制 二:单纯的(伪生命周期)

    转载于:http://blog.csdn.net/yuanzeyao/article/details/38025165 在前一篇文章中,我主要讲解了Android源码中的Touch事件的传递过程,现在 ...

  3. Android touch事件的派发流程

    Android TouchEvent事件传递机制 通俗易懂,能够了解Touch事件派发的基本流程. Android中的dispatchTouchEvent().onInterceptTouchEven ...

  4. Android Touch事件传递机制 二:单纯的(伪生命周期) 这个清楚一点

    转载于:http://blog.csdn.net/yuanzeyao/article/details/38025165 在前一篇文章中,我主要讲解了Android源码中的Touch事件的传递过程,现在 ...

  5. Android Touch事件传递机制详解 下

    尊重原创:http://blog.csdn.net/yuanzeyao/article/details/38025165 资源下载:http://download.csdn.net/detail/yu ...

  6. Android Touch事件传递机制具体解释 下

    尊重原创:http://blog.csdn.net/yuanzeyao/article/details/38025165 资源下载:http://download.csdn.net/detail/yu ...

  7. Android Touch事件分发过程

    虽然网络上已经有非常多关于这个话题的优秀文章了,但还是写了这篇文章,主要还是为了加强自己的记忆吧,自己过一遍总比看别人的分析要深刻得多.那就走起吧. 简单演示样例 先看一个演示样例 : 布局文件 : ...

  8. Android Touch事件传递机制具体解释 上

    尊重原创:http://blog.csdn.net/yuanzeyao/article/details/37961997 近期总是遇到关于Android Touch事件的问题,如:滑动冲突的问题,曾经 ...

  9. Android Touch事件之二:dispatchTouchEvent()和onTouchEvent()篇

    2015-12-01 15:06:14 Android Touch事件第一篇:Touch事件在父ViewGroup和子View之间的传递简单分析了事件的传递流程,这次深入了解下dispatchTouc ...

随机推荐

  1. MYI 文件内容

    参考 http://blog.itpub.net/703656/viewspace-1018470/ 创建表结构 create table test(name char(20), age int, c ...

  2. OK335xS can't reset with reboot

    /*********************************************************************** * OK335xS can't reset * 说明: ...

  3. I.MX6 android shutdown 内核崩溃

    /**************************************************************************** * I.MX6 android shutdo ...

  4. 在 Azure 中使用公用 IP 创建多 NIC VM

    Russ Slaten  2014年 11 月 18日下午 4点 我们最近宣布了支持具有多个网络接口控制器 (NIC) 的虚拟机 (VM).我仍在努力了解此功能适用的所有新场景,但首先,我希望亲自测试 ...

  5. 进程间通信七 (socket)

    copyright:weishusheng          data:2015.5.26              摘要:socket又叫套接字或者插口,它也是进程间通信的一种方式,实际上就是网络上 ...

  6. (一)学习JavaScript之setTimeout方法

    参考:http://www.w3school.com.cn/jsref/met_win_settimeout.asp HTML DOM Window 对象 定义和用法 setTimeout() 方法用 ...

  7. MVC的EF编辑,不用查询直接修改

    EF中会为每个 管理的 实体对象 创建一个代理包装类对象,其中会跟踪 实体对象 的状态和每个属性的状态: 一.通常使用EF更新的方式,先查询出要修改的数据,然后再修改新的值:实体对象被修改的属性 在 ...

  8. javascript六难题

    1.下面代码的运行效果是什么?为什么? <html> <head> <meta charset="utf-8"> <title>DO ...

  9. windows和linux间互传文件

    方法1:Xshell传输文件 用rz,sz命令在xshell传输文件 很好用,然后有时候想在windows和linux上传或下载某个文件,其实有个很简单的方法就是rz,sz 首先你的Ubuntu需要安 ...

  10. 咨询内容: TF卡一定要重新买吗,为什么我的放进去读不了呢

    京东回复:您好!先科(SAST) SA-992 便携数码音响 (兰色)不用重新买,但是需要您采用FAT分区重新格式化,感谢您对京东的支持!祝您购物愉快!