原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://glblong.blog.51cto.com/3058613/1559320

   其他相关博文:

   Android笔记:触摸事件的分析与总结----MotionEvent对象

   Android笔记:触摸事件的分析与总结----TouchEvent处理机制

Android中的事件类型分为按键事件和屏幕触摸事件。TouchEvent是屏幕触摸事件的基础事件,要深入了解屏幕触摸事件的处理机制,就必须掌握TouchEvent在整个触摸事件中的转移和处理过程。此处将对TouchEvent处理机制的学习做个小小的总结和备记。

当屏幕中包含一个ViewGroup,而这个ViewGroup又包含一个子view,这个时候android系统如何处理Touch事件呢?到底是 ViewGroup来处理Touch事件,还是子view来处理Touch事件呢?

这问题涉及到与每个View或者ViewGroup的子类都具有的三个和TouchEvent处理密切相关的方法:

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

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

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

其中view类和Activity中都有dispatchTouchEvent()和onTouchEvent()两个方法。ViewGroup继承自View,而且还新添了一个onInterceptTouchEvent()方法。

这三个方法的返回值都是boolean值,对于返回结果,如果return true,那么表示该方法消费了此次事件,如果return false,那么表示该方法并未处理完全,该事件仍然需要以某种方式传递下去继续等待处理。

一、dispatchTouchEvent

dispatchTouchEvent(MotionEventev) 这个方法用来分发TouchEvent,默认返回false。

先看下Activity中的注释和方法:

   /*** Called to process touch screen events.  You can override this to* intercept all touch screen events before they are dispatched to the* window.  Be sure to call this implementation for touch screen events* that should be handled normally.* * @param ev The touch screen event.* * @return boolean Return true if this event was consumed.*/public boolean dispatchTouchEvent(MotionEvent ev){if (ev.getAction() == MotionEvent.ACTION_DOWN){onUserInteraction();}if (getWindow().superDispatchTouchEvent(ev)){return true;}return onTouchEvent(ev);}

onInterceptTouchEvent()默认返回了false,注释的大意为重写该方法可以实现对触屏事件的拦截,使用该方法需要特别注意的是,该方法与View类的onTouchEvent(MotionEvent)或者View.onTouchEvent(MotionEvent)方法具有复杂的关联机制。结合onTouchEvent(),总结下onInterceptTouchEvent()大致的规则为:

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()处理。

三、onTouchEvent

onTouchEvent()的处理机制详见此文:

Android笔记:触摸事件的分析与总结----MotionEvent对象

四、TouchEvent处理范例

此处创建一个包含自定义LinearLayout(ViewGroup类)和自定义TextView(View类)的Activity来分析触摸屏幕时TouchEvent的处理机制。

效果图如下:

<?xml version="1.0" encoding="utf-8"?>
<com.example.d_touchevent.MyLinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center" > <com.example.d_touchevent.MyTextView android:layout_width="100dp" android:layout_height="100dp" android:id="@+id/tv" android:text="测试" android:textSize="40sp" android:textStyle="bold" android:background="#F0F00F" android:textColor="#0000FF"/>
</com.example.d_touchevent.MyLinearLayout>

MainActivity.java代码如下:

package com.example.d_touchevent;import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.MotionEvent;/*** 参考资料:http://glblong.blog.51cto.com/3058613/1559320* @author zeng**/
public class MainActivity extends Activity
{private String TAG = "Activity ---  ";@Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}@Overridepublic boolean onTouchEvent(MotionEvent event){boolean b = super.onTouchEvent(event);int action = event.getAction();switch (action){case MotionEvent.ACTION_DOWN:Log.e(TAG , "ACTION_DOWN   --- " + TAG + "onTouchEvent          处理 --- " + b);break;case MotionEvent.ACTION_MOVE:Log.e(TAG, "ACTION_MOVE    --- " + TAG + "onTouchEvent          处理 --- " + b);break;case MotionEvent.ACTION_UP:Log.e(TAG, "ACTION_UP     --- " + TAG + "onTouchEvent          处理 --- " + b);break;case MotionEvent.ACTION_CANCEL:Log.e(TAG, "ACTION_CANCEL --- " + TAG + "onTouchEvent          处理 --- " + b);break;}return b;}@Overridepublic boolean dispatchTouchEvent(MotionEvent ev){int action = ev.getAction();switch (action){case MotionEvent.ACTION_DOWN:Log.e(TAG, "ACTION_DOWN   --- " + TAG + "dispatchTouchEvent    分发 --- ");break;case MotionEvent.ACTION_MOVE:Log.e(TAG, "ACTION_MOVE   --- " + TAG + "dispatchTouchEvent    分发 --- ");break;case MotionEvent.ACTION_UP:Log.e(TAG, "ACTION_UP     --- " + TAG + "dispatchTouchEvent    分发 --- ");break;case MotionEvent.ACTION_CANCEL:Log.e(TAG, "ACTION_CANCEL --- " + TAG + "dispatchTouchEvent    分发 --- ");break;}return super.dispatchTouchEvent(ev);}}

MyLinearLayout.java代码如下:

package com.example.d_touchevent;import android.widget.LinearLayout;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;/*** 参考资料:http://glblong.blog.51cto.com/3058613/1559320* @author zeng**/
public class MyLinearLayout extends LinearLayout
{private final String TAG = "L布局    ---  ";public MyLinearLayout(Context context, AttributeSet attrs){super(context, attrs);Log.e(TAG, TAG);}@Overridepublic boolean dispatchTouchEvent(MotionEvent ev){int action = ev.getAction();switch (action){case MotionEvent.ACTION_DOWN:Log.e("", " ");Log.e("", " ");Log.e(TAG, "ACTION_DOWN   --- " + TAG + "dispatchTouchEvent    分发 --- ");break;case MotionEvent.ACTION_MOVE:Log.e(TAG, "ACTION_MOVE   --- " + TAG + "dispatchTouchEvent    分发 --- ");break;case MotionEvent.ACTION_UP:Log.e(TAG, "ACTION_UP     --- " + TAG + "dispatchTouchEvent    分发 --- ");break;case MotionEvent.ACTION_CANCEL:Log.e(TAG, "ACTION_CANCEL --- " + TAG + "dispatchTouchEvent    分发 --- ");break;}return super.dispatchTouchEvent(ev);}@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev){boolean b = false;int action = ev.getAction();switch (action){case MotionEvent.ACTION_DOWN:Log.e(TAG, "ACTION_DOWN   --- " + TAG + "onInterceptTouchEvent 拦截 --- " + b);break;case MotionEvent.ACTION_MOVE:Log.e(TAG, "ACTION_MOVE   --- " + TAG + "onInterceptTouchEvent 拦截 --- " + b);break;case MotionEvent.ACTION_UP:Log.e(TAG, "ACTION_UP     --- " + TAG + "onInterceptTouchEvent 拦截 --- " + b);break;case MotionEvent.ACTION_CANCEL:Log.e(TAG, "ACTION_CANCEL --- " + TAG + "onInterceptTouchEvent 拦截 --- " + b);break;}return b;}@Overridepublic boolean onTouchEvent(MotionEvent ev){boolean b = true;int action = ev.getAction();switch (action){case MotionEvent.ACTION_DOWN:Log.e(TAG, "ACTION_DOWN   --- " + TAG + "onTouchEvent          处理 --- " + b);break;case MotionEvent.ACTION_MOVE:Log.e(TAG, "ACTION_MOVE   --- " + TAG + "onTouchEvent          处理 --- " + b);break;case MotionEvent.ACTION_UP:Log.e(TAG, "ACTION_UP     --- " + TAG + "onTouchEvent          处理 --- " + b);break;case MotionEvent.ACTION_CANCEL:Log.e(TAG, "ACTION_CANCEL --- " + TAG + "onTouchEvent          处理 --- " + b);break;}return b;}
}

MyTextView.java代码如下:

package com.example.d_touchevent;import android.widget.TextView;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;/*** 参考资料:http://glblong.blog.51cto.com/3058613/1559320* @author zeng**/
public class MyTextView extends TextView
{private final String TAG = "TextView ---  ";public MyTextView(Context context, AttributeSet attrs){super(context, attrs);}@Overridepublic boolean dispatchTouchEvent(MotionEvent ev){int action = ev.getAction();switch (action){case MotionEvent.ACTION_DOWN:Log.e(TAG, "ACTION_DOWN   --- " + TAG + "dispatchTouchEvent    分发 --- ");break;case MotionEvent.ACTION_MOVE:Log.e(TAG, "ACTION_MOVE   --- " + TAG + "dispatchTouchEvent    分发 --- ");break;case MotionEvent.ACTION_UP:Log.e(TAG, "ACTION_UP     --- " + TAG + "dispatchTouchEvent    分发 --- ");break;case MotionEvent.ACTION_CANCEL:Log.e(TAG, "ACTION_CANCEL --- " + TAG + "dispatchTouchEvent    分发 --- ");break;}return super.dispatchTouchEvent(ev);}@Overridepublic boolean onTouchEvent(MotionEvent ev){boolean b = false;int action = ev.getAction();switch (action){case MotionEvent.ACTION_DOWN:Log.e(TAG, "ACTION_DOWN   --- " + TAG + "onTouchEvent          处理 --- " + b);break;case MotionEvent.ACTION_MOVE:Log.e(TAG, "ACTION_MOVE   --- " + TAG + "onTouchEvent          处理 --- " + b);break;case MotionEvent.ACTION_UP:Log.e(TAG, "ACTION_UP     --- " + TAG + "onTouchEvent          处理 --- " + b);break;case MotionEvent.ACTION_CANCEL:Log.e(TAG, "ACTION_CANCEL --- " + TAG + "onTouchEvent          处理 --- " + b);break;}return b;}}

五、范例运行分析

注:a.以下Logcat中,若没有特别说明,dispatchTouchEvent()都按默认方法返回false。

b.为方便,L布局简写为L,TextView简写为T,Activity简写为A,下同。

1)点击范例中的【测试】按钮,运行日志如下:

结论:

当ACTION_DOWN事件产生时,首先触发了Activity的dispatchTouchEvent()方法;接着传递到ViewGroup上,触发L布局的dispatchTouchEvent()方法继续分发TouchEvent;L布局的onInterceptTouchEvent()方法为false,即不会拦截TouchEvent的传递,因而继续传递到ViewGroup里的View对象TextView中,此时仍然先是调用了TextView的dispatchTouchEvent()方法来处理TouchEvent的分发。从上到下依次传递:Activity -> L布局 -> TextView。

同理,当ACTION_UP事件产生时,首先也是Activity的dispatchTouchEvent()方法,接着再到L布局的dispatchTouchEvent()方法。

2)L.dispatchTouchEvent() = true ,运行日志如下:

   结论:

   此时,每个触摸事件产生时,都只执行到L布局的dispatchTouchEvent()方法,而不会继续再传递并触发其他方法。

3)A.dispatchTouchEvent() = false  &&  L.dispatchTouchEvent() = false  &&  T.dispatchTouchEvent() = true,运行日志如下:

结论:

由上可见,当TouchEvent由Activity传递到TextView时,执行到dispatchTouchEvent()后便结束了。也就是到TextView时,Android系统认为ACTION_DOWN和ACITON_UP都已经被消费了,而没有继续分发下去。

4)L.onInterceptTouchEvent = true   &&   L.onTouchEvent = true ,运行日志如下:

结论:

这种情况下,L布局处理了所有的TouchEvent。

5)L.onInterceptTouchEvent = true   &&   L.onTouchEvent = false , 运行日志如下:

   结论:

L布局只处理了ACTION_DOWN事件,而L布局最外层的ctivity处理了TouchEvent。

6)L.onInterceptTouchEvent=false  &&  L.onTouchEvent=true  &&  T.onTouchEvent=true , 运行日志如下:

结论:

TouchEvent完全由TextView处理。

7)L.onInterceptTouchEvent=false  &&  L.onTouchEvent=true  &&  T.onTouchEvent=false , 运行日志如下:

结论:

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

六、分析总结

1.三个主要相关的方法的默认值

所有dispatchTouchEvent方法的默认值都是false。

ViewGroup里的onInterceptTouchEvent默认值是false这样才能把事件传给View里的onTouchEvent.

Activity和ViewGroup里的onTouchEvent默认值都是false。

View里的onTouchEvent返回默认值是true.这样才能执行多次touch事件。

2.TouchEvent的处理流程

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

3.TouchEvent的处理流程图

自己制作了个TouchEvent处理的流程图,方便理清TouchEvent事件在各种UI对象以及对应方法中的处理机制。将流程图与上面的运行日志结合分析,发现对TouchEvent处理的机制清晰了很多。若有错误之处,欢迎指教。

转载于:https://www.cnblogs.com/xiaorenwu702/p/4018608.html

Android笔记:触摸事件的分析与总结----TouchEvent处理机制相关推荐

  1. android 触摸事件 控制,Android笔记:触摸事件的分析与总结----TouchEvent处理机制

    其他相关博文: Android中的事件类型分为按键事件和屏幕触摸事件.TouchEvent是屏幕触摸事件的基础事件,要深入了解屏幕触摸事件的处理机制,就必须掌握TouchEvent在整个触摸事件中的转 ...

  2. Android笔记:触摸事件的分析与总结----多点触控

       其他相关博文:    Android笔记:触摸事件的分析与总结----MotionEvent对象    Android笔记:触摸事件的分析与总结----TouchEvent处理机制     An ...

  3. Android触摸事件传递分析与实践

    设计UI时,亲爱的交互设计师们总会有一些天马行空的想法,大多数情况下原生的控件已不能支持这些"看似简单"的交互逻辑,需要继承ListView.ViewPager.ScrollVie ...

  4. Android 系统(74)---Android手势触摸事件的分发和消费机制

    Android手势&触摸事件的分发和消费机制 在Android 客户端开发过程中,经常会遇到手势事件的处理,本篇博文讲一下本人对touch事件处理机制的一些理解,希望对一些初级开发者有所帮助. ...

  5. android方向触摸事件,Android触摸事件传递机制,这一篇就够了

    整个触摸事件牵涉到的是,Activity,View,ViewGroup三者的传递机制. 这个触摸事件就是从外层往内层一层层的传递. 整个传递机制,分为3个步骤:分发,拦截,和消费. 1. 触摸事件的类 ...

  6. Android 中触摸事件与点击事件分析

    触摸事件 两种检测触摸事件的方式: 设置触摸监听  setOnTouchListener 返回 true: 表示消费事件 , 可以检测到 down/move/up 事件 返回 false: 不消费事件 ...

  7. 红橙Darren视频笔记 ViewGroup事件分发分析 基于API27

    本节目标,通过案例,先看程序运行结果,然后跟踪源码,理解为什么会有这样的输出,继而理解view group的分发机制,感觉和证明题很像呢. 考虑以下程序的运行结果: case1: public cla ...

  8. android 屏幕触摸事件及处理机制解读

    原创性声明:本文系作者原创,转载请附原文地址:http://blog.csdn.net/a774057695/article/details/49336123 最近实在太忙,没有写多少东西,上次承诺写 ...

  9. android触摸事件触摸点坐标,Android开发——触摸事件TouchEvent详解及其应用

    2020.8.8 Activity的功能: 1.管理界面的生命周期 2.接收事件(触摸事件) 一.触摸事件传递解析 touch事件的传递.png 当手指按下时会首先调用onUserInteractio ...

  10. android方向触摸事件,Android触摸事件如何传递?

    慕工程0101907 让我们看一个视觉示例.在此处输入图片说明发生触摸事件时,首先会向每个人通知该事件,从活动开始,一直到顶部的视图.然后,每个人都有机会处理该事件,从顶部的视图(触摸区域中Z顺序最高 ...

最新文章

  1. python编程基础教程-史上最全Python编程基础入门教程
  2. 【新版上线】网易云点播内容加密服务正式发布啦!
  3. ARM 汇编中的 B . 语句意义
  4. 职称计算机隐藏桌面图标,2018年职称计算机考试WindowsXP操作题(1)
  5. Redis之压缩列表ziplist
  6. oracle中packages使用,oracle中packages的使用
  7. git项目根据不同需求进行独立开发
  8. 全新胶囊网络Efficient-CapsNet效果显著!
  9. SCCM 2012 SP1系列(一)先决条件准备-1
  10. 为什么dubbo使用ZkClient作为zookeeper的客户端
  11. Parcelable接口的使用
  12. 视觉SLAM十四讲学习笔记-第七讲-视觉里程计-ICP和实践
  13. robo3T篇 — robo3T的使用说明
  14. VxWorks6.8串口示例
  15. linux系统不能用投影仪,Linux连接投影仪(ubuntu)失败或显示不正常--未测试
  16. 使用vue制作网页导航栏
  17. 机器人对话常用语模板_世界首个机器人观音在岛国问世,请问AI开光还会远吗?...
  18. Android 11 强制分区存储
  19. 超松弛迭代法求解二维电磁场有限差分方程(附Matlab代码)
  20. 笔记:springboot-admin 整合spring security应用注册失败问题

热门文章

  1. java getResourceAsStream方法
  2. Zephry_GPIO的中断使用详解以及中断原理
  3. NoSQL——MongoDB
  4. Ansible之roles使用
  5. [js高手之路] dom常用节点属性兼容性详解与应用
  6. DataGridView使用技巧二:设置单元格只读
  7. Qt中的对话框(模态,非模态,关于,问题,文件)
  8. zw版【转发·台湾nvp系列Delphi例程】.NET调用HALCON COM控件内存释放模式
  9. 没事不要在for循环期间增减迭代序列的成员
  10. RMAN-06217: 错误