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. <?xmlversion="1.0"encoding="utf-8"?>
  2. <test.lzqdiy.MyLinearLayoutxmlns: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. packagetest.lzqdiy;
  2. importandroid.app.Activity;
  3. importandroid.os.Bundle;
  4. publicclassTestTouchEventAppextendsActivity{
  5. /**Calledwhentheactivityisfirstcreated.*/
  6. @Override
  7. publicvoidonCreate(BundlesavedInstanceState){
  8. super.onCreate(savedInstanceState);
  9. setContentView(R.layout.main);
  10. }
  11. }
  12. packagetest.lzqdiy;
  13. importandroid.content.Context;
  14. importandroid.util.AttributeSet;
  15. importandroid.util.Log;
  16. importandroid.view.MotionEvent;
  17. importandroid.widget.LinearLayout;
  18. publicclassMyLinearLayoutextendsLinearLayout{
  19. privatefinalStringTAG="MyLinearLayout";
  20. publicMyLinearLayout(Contextcontext,AttributeSetattrs){
  21. super(context,attrs);
  22. Log.d(TAG,TAG);
  23. }
  24. @Override
  25. publicbooleandispatchTouchEvent(MotionEventev){
  26. intaction=ev.getAction();
  27. switch(action){
  28. caseMotionEvent.ACTION_DOWN:
  29. Log.d(TAG,"dispatchTouchEventaction:ACTION_DOWN");
  30. break;
  31. caseMotionEvent.ACTION_MOVE:
  32. Log.d(TAG,"dispatchTouchEventaction:ACTION_MOVE");
  33. break;
  34. caseMotionEvent.ACTION_UP:
  35. Log.d(TAG,"dispatchTouchEventaction:ACTION_UP");
  36. break;
  37. caseMotionEvent.ACTION_CANCEL:
  38. Log.d(TAG,"dispatchTouchEventaction:ACTION_CANCEL");
  39. break;
  40. }
  41. returnsuper.dispatchTouchEvent(ev);
  42. }
  43. @Override
  44. publicbooleanonInterceptTouchEvent(MotionEventev){
  45. intaction=ev.getAction();
  46. switch(action){
  47. caseMotionEvent.ACTION_DOWN:
  48. Log.d(TAG,"onInterceptTouchEventaction:ACTION_DOWN");
  49. break;
  50. caseMotionEvent.ACTION_MOVE:
  51. Log.d(TAG,"onInterceptTouchEventaction:ACTION_MOVE");
  52. break;
  53. caseMotionEvent.ACTION_UP:
  54. Log.d(TAG,"onInterceptTouchEventaction:ACTION_UP");
  55. break;
  56. caseMotionEvent.ACTION_CANCEL:
  57. Log.d(TAG,"onInterceptTouchEventaction:ACTION_CANCEL");
  58. break;
  59. }
  60. returnfalse;
  61. }
  62. @Override
  63. publicbooleanonTouchEvent(MotionEventev){
  64. intaction=ev.getAction();
  65. switch(action){
  66. caseMotionEvent.ACTION_DOWN:
  67. Log.d(TAG,"---onTouchEventaction:ACTION_DOWN");
  68. break;
  69. caseMotionEvent.ACTION_MOVE:
  70. Log.d(TAG,"---onTouchEventaction:ACTION_MOVE");
  71. break;
  72. caseMotionEvent.ACTION_UP:
  73. Log.d(TAG,"---onTouchEventaction:ACTION_UP");
  74. break;
  75. caseMotionEvent.ACTION_CANCEL:
  76. Log.d(TAG,"---onTouchEventaction:ACTION_CANCEL");
  77. break;
  78. }
  79. returntrue;
  80. }
  81. }
  82. packagetest.lzqdiy;
  83. importandroid.content.Context;
  84. importandroid.util.AttributeSet;
  85. importandroid.util.Log;
  86. importandroid.view.MotionEvent;
  87. importandroid.widget.TextView;
  88. publicclassMyTextViewextendsTextView{
  89. privatefinalStringTAG="MyTextView";
  90. publicMyTextView(Contextcontext,AttributeSetattrs){
  91. super(context,attrs);
  92. }
  93. @Override
  94. publicbooleandispatchTouchEvent(MotionEventev){
  95. intaction=ev.getAction();
  96. switch(action){
  97. caseMotionEvent.ACTION_DOWN:
  98. Log.d(TAG,"dispatchTouchEventaction:ACTION_DOWN");
  99. break;
  100. caseMotionEvent.ACTION_MOVE:
  101. Log.d(TAG,"dispatchTouchEventaction:ACTION_MOVE");
  102. break;
  103. caseMotionEvent.ACTION_UP:
  104. Log.d(TAG,"dispatchTouchEventaction:ACTION_UP");
  105. break;
  106. caseMotionEvent.ACTION_CANCEL:
  107. Log.d(TAG,"onTouchEventaction:ACTION_CANCEL");
  108. break;
  109. }
  110. returnsuper.dispatchTouchEvent(ev);
  111. }
  112. @Override
  113. publicbooleanonTouchEvent(MotionEventev){
  114. intaction=ev.getAction();
  115. switch(action){
  116. caseMotionEvent.ACTION_DOWN:
  117. Log.d(TAG,"---onTouchEventaction:ACTION_DOWN");
  118. break;
  119. caseMotionEvent.ACTION_MOVE:
  120. Log.d(TAG,"---onTouchEventaction:ACTION_MOVE");
  121. break;
  122. caseMotionEvent.ACTION_UP:
  123. Log.d(TAG,"---onTouchEventaction:ACTION_UP");
  124. break;
  125. caseMotionEvent.ACTION_CANCEL:
  126. Log.d(TAG,"---onTouchEventaction:ACTION_CANCEL");
  127. break;
  128. }
  129. returntrue;
  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。

更多相关文章

  1. Android高手进阶教程(二十二)之---Android中几种图像特效处理的
  2. Android(安卓)双指同时点击事件模拟
  3. Android的子线程能更新UI吗?
  4. Android开发中高效的数据结构用SparseArray代替HashMap
  5. Android(安卓)屏幕旋转 处理 AsyncTask 和 ProgressDialog 的最
  6. ListView setOnItemClickListener无效原因详细分析
  7. ListView setOnItemClickListener无效原因分析
  8. 利用百度词典API和Volley网络库开发的android词典应用
  9. Android(安卓)中全局键的处理GlobalKeyManager

随机推荐

  1. [android]android-am命令的使用
  2. Android Studio 默认keystore 以及自定义
  3. 理解Android的layout和measure
  4. Android 中的WiFi学习笔记----WIFI启动
  5. android平台移植总结
  6. VMware安装Android全解
  7. 《大话移动APP测试:Android与iOS应用测试
  8. Android -SQLite数据库存储
  9. Android RabbitMQ之Android初探
  10. Android禁止EditText自动弹出软键盘的方