前言

  Android中关于触摸事件的分发传递是一个很值得研究的东西。曾不见你引入了一个ListView的滑动功能,ListView就不听你手指的指唤来滚动了;也不知道为啥Button设置了onClick和onTouch,其中谁会先响应;或许你会问onTouch和onTouchEvent有什么区别,又该如何使用?这里一切的一切,只要你了解了事件分发机制,你会发现,解释这都不是事儿!

相关Touch事件的方法

1、public boolean dispatchTouchEvent(MotionEvent ev)                ————事件分发方法,分发Event所调用

2、public boolean onInterceptTouchEvent(MotionEvent ev)    ————事件拦截方法,拦截Event所调用

3、public boolean onTouchEvent(MotionEvent event)       ————事件响应方法,处理Event所调用

拥有上述事件的类

1、Activity类(Activity及其各种继承子类)

    dispatchTouchEvent()、onTouchEvent()

2、ViewGroup类(LinearLayout、FrameLayout、ListView等.....)

    dispatchTouchEvent()、onInterceptTouchEvent()、onTouchEvent()

3、View类(Button、TextView等.....)

    dispatchTouchEvent()、onTouchEvent()

PS:需要特别注意一点就是ViewGroup中额外拥有onInterceptTouchEvent()方法,其他两个方法为这三种类所共同拥有。

方法的简单用途解析

我们可以发现这三个方法的返回值都为boolean类型,其实它们就是通过返回值来决定下一步的传递处理方向。

1、dispatchTouchEvent()  ——用来分发事件所用

  该方法会将根元素的事件自上而下依次分发到内层子元素中,直到被终止或者到达最里层元素,该方法也是采用一种隧道方式来分发。在其中会调用onInterceptTouchEvent()和onTouchEvent(),一般不会去重写。

  返回false则不拦截继续往下分发,如果返回true则拦截住该事件不在向下层元素分发,在dispatchTouchEvent()方法中默认返回false。

2、onInterceptTouchEvent()  ——用来拦截事件所用

  该方法在ViewGroup源代码中实现就是返回false不拦截事件,Touch事件就会往下传递给其子View。

  如果我们重写该方法并且将其返回true,该事件将会被拦截,并且被当前ViewGroup处理,调用该类的onTouchEvent()方法。

3、onTouchEvent()  ——用来处理事件

  返回true则表示该View能处理该事件,事件将终止向上传递(传递给其父View)

  返回false表示不能处理,则把事件传递给其父View的onTouchEvent()方法来处理

实战演练

  好了,基础知识讲完了,上面的东西看不懂不要紧,现在要睁大眼睛好好看了,因为下面开始用例子讲解Touch的事件分发机制,相信能让大家更好的理解这个分发机制。

在这个例子中,我们需要重写四个类:

1、老板  ——>  MyActivity

2、经理  ——>  FrameLayout

3、组长  ——>  LineaLayout

4、员工  ——>  TextView

软件界面图如下:

搞个通俗易懂的例子开开头

老板对部长说:我要吃红烧鱼
部长对经理说:你做个红烧鱼
经理对组长说:你做个红烧鱼
组长对员工说:你做个红烧鱼
   ……(员工做呀做,没把鱼烧出来)
员工说:我都通宵加班了还是没做出来,别扣我工资行吗
组长说:你个笨蛋,白发你工资,下次不找你了,我自己搞
   ……(组长做呀做,还是没做出来)
组长对经理说:我尽力了,还是没做出来,千万别炒我鱿鱼呀
经理说:你个废物,这点都做不好,只能我自己来做了
   ……(经理做呀做,做成功了)
经理对部长说:红烧鱼做好了
部长回应说:不错,下次有事还找你
部长对老板说:红烧鱼做好了
老板回应说:不错,下次有事还找你
---------------------------
老板对部长说:我要吃水煮鱼
部长对经理说:你做个水煮鱼
经理自己想想:组长连红烧鱼都搞不定,这次就不找他了,我自己亲自来做
 ……(经理做呀做,又成功了)
经理对部长说:红烧鱼做好了
部长回应说:不错,下次有事还找你
部长对老板说:红烧鱼做好了
老板回应说:不错,下次有事还找你
---------------------------

1、按常理,领导都会把任务向下分派,一旦下面的人把事情做不好,就不会再把后续的任务交给下面的人来做了,只能自己亲自做,如果自己也做不了,就只能告诉上级不能完成任务,上级又会重复他的过程。

2、另外,领导都有权利拦截任务,对下级隐瞒该任务,而直接自己去做,如果做不成,也只能向上级报告不能完成任务。

流程演示

【1】、我们假设员工能力不足,也就是将TextView的onTouchEvent()方法设置返回false,表示其不能消费该事件。

事件传递的流程:

【2】、我们假设员工能处理该事件,也就是将TextView的onTouchEvent()方法设置返回true,表示其能处理该事件。

事件传递的流程:

【3】、我们假设员工和组长能力不足,即TextView和LinearLayout的onTouch()返回false,但是经理解决了该问题,即FrameLayout的onTouch()返回true

事件传递的流程:

【4】假设我们的组长在事件分发到他那里的时候,决定拦截下来不交给下面的员工,也就是onInterceptTouchEvent()返回为true,并且他也成功完成了任务,即onTouchEvent()返回值为true。

事件传递的流程:

做个小结

1、很明显,这些流程就是dispatchTouchEvent()的处理结果,但是前提是我们不去完全的重新实现这个方法,也就是保证需要return super.dispatchTouchEvent(ev);来确定父类的方法有被调用。而这些事件将会由上而下的逐层传递,直到传递到最底层的View元素,此时将会调用该View的onTouchEvent()方法来处理该事件;返回true来表示对该事件已经成功处理,如果返回false则并没有成功处理事件,将会把事件逐层向上传递,交给上层View的onTouchEvent()方法处理,以此类推,直至某一View成功处理该事件,或者到顶层View处理仍然返回false则放弃对该事件处理,事件消失。

2、如果在事件向下传递的过程中,被中途拦截,也就是View的onInterceptTouchEvent()方法返回true,那么该事件将停止向下传递,并交给该层的onTouchEvent()方法处理,无论处理成功与否,底层View将再也不会接收到该事件。PS:若处理失败,则会交由上层View的onTouchEvent()方法处理。

3、dispatchTouchEvent()具有记忆的功能,如果第一次事件向下传递到某View,它把事件继续传递交给它的子View,它会记录该事件是否被它下面的View给处理成功了,(怎么能知道呢?如果该事件会再次被向上传递到我这里来由我的onTouchEvent()来处理,那就说明下面的View都没能成功处理该事件);当第二次事件向下传递到该View,该View的dispatchTouchEvent()方法机会判断,若上次的事件由下面的view成功处理了,那么这次的事件就继续交给下面的来处理,若上次的事件没有被下面的处理成功,那么这次的事件就不会向下传递了,该View直接调用自己的onTouchEvent()方法来处理该事件。

4、记忆功能的信息只在一系列事件完成之前有效,如从ACTION_DOWN事件开始,直到后续事件ACTION_MOVE,ACTION_UP结束后,“记忆”的信息就会清除。也就是说如果某View处理ACTION_DOWN事件失败了(onTouchEvent()返回false),那么后续的ACTION_MOVE,ACTION_UP等事件就不会再传递到该View了,由其父View自己来处理。在下一次发生ACTION_DOWN事件的时候,还是会传递到该View的。

附带代码

1、MyActivity

public class MyActivity extends ActionBarActivity {

    @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
} @Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.i("test", "【老板】下达任务:" + Util.actionToString(ev.getAction()) + ",找个人帮我完成,任务往下分发。");
return super.dispatchTouchEvent(ev);
} @Override
public boolean onTouchEvent(MotionEvent event) {
boolean relust = false;
Log.i("test", "【老板】完成任务:" + Util.actionToString(event.getAction()) + ",【经理】太差劲了,以后不再找你干活了,我自来搞定!是否解决:" + Util.canDoTaskTop(relust));
return relust;
} }

2、MyFrameLayout:

public class MyFrameLayout extends FrameLayout {

    public MyFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
} @Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.i("test", "【经理】下达任务:" + Util.actionToString(ev.getAction()) + ",找个人帮我完成,任务往下分发。");
return super.dispatchTouchEvent(ev);
} @Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean relust = false;
Log.i("test", "【经理】是否拦截任务:" + Util.actionToString(ev.getAction()) + ",拦下来?" + relust);
return relust;
} @Override
public boolean onTouchEvent(MotionEvent event) {
boolean relust = true;
Log.i("test", "【经理】完成任务:" + Util.actionToString(event.getAction()) + ",【组长】太差劲了,以后不再找你干活了,我自来搞定!是否解决:" + Util.canDoTask(relust));
return relust;
}
}

3、MyLinearLayout

public class MyLinearLayout extends LinearLayout {

    public MyLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
} @Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.i("test", "【组长】下达任务:" + Util.actionToString(ev.getAction()) + ",找个人帮我完成,任务往下分发。");
return super.dispatchTouchEvent(ev);
} @Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean relust = true;
Log.i("test", "【组长】是否拦截任务:" + Util.actionToString(ev.getAction()) + ",拦下来?" + relust);
return relust;
} @Override
public boolean onTouchEvent(MotionEvent event) {
boolean relust = true;
Log.i("test", "【组长】完成任务:" + Util.actionToString(event.getAction()) + ",【员工】太差劲了,以后不再找你干活了,我自来搞定!是否解决:" + Util.canDoTask(relust));
return relust;
}
}

4、MyTextView

public class MyTextView extends TextView {

    public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
} @Override
public boolean dispatchTouchEvent(MotionEvent event) {
Log.i("test", "【员工】下达任务:" + Util.actionToString(event.getAction()) + ",我没手下了,唉~自己干吧");
return super.dispatchTouchEvent(event);
} @Override
public boolean onTouchEvent(MotionEvent event) {
boolean relust = false;
Log.i("test", "【员工】完成任务:" + Util.actionToString(event.getAction()) + ",【员工】现在只能靠自己了!是否解决:" + Util.canDoTask(relust));
return relust;
}
}

5、Util(工具类)

public class Util {
public static String actionToString(int action){
String result = null;
switch(action){
case MotionEvent.ACTION_DOWN:
result = "ACTION_DOWN";
break;
case MotionEvent.ACTION_MOVE:
result = "ACTION_MOVE";
break;
case MotionEvent.ACTION_UP:
result = "ACTION_UP";
break;
}
return result;
}
public static String canDoTask(boolean can){
String result = null;
if(can){
result = "完美解决该任务!";
}
else{
result = "这活搞不定,交给老大完成吧。";
}
return result;
}
public static String canDoTaskTop(boolean can){
String result = null;
if(can){
result = "完美解决该任务!";
}
else{
result = "这活搞不定,放弃该任务。";
}
return result;
}
}

作者:enjoy风铃
出处:http://www.cnblogs.com/net168/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则下次不给你转载了

Android的Touch事件分发机制简单探析的更多相关文章

  1. Android中的事件分发机制

    Android中的事件分发机制 作者:丁明祥 邮箱:2780087178@qq.com 这篇文章这周之内尽量写完 参考资料: Android事件分发机制完全解析,带你从源码的角度彻底理解(上) And ...

  2. Android Touch事件分发机制学习

    Android  事件分发机制 ViewGroup dispatchTouchEvent 返回true dispatchTouchEvent: Activity ACTION_DOWN Myrelat ...

  3. Android开发之Touch事件分发机制

    原地址http://www.cnblogs.com/linjzong/p/4191891.html Touch事件分发中只有两个主角:ViewGroup和View.Activity的Touch事件事实 ...

  4. Android事件分发机制(二)30分钟弄明白Touch事件分发机制

    Touch事件分发中只有两个主角:ViewGroup和View.Activity的Touch事件事实上是调用它内部的ViewGroup的Touch事件,可以直接当成ViewGroup处理. View在 ...

  5. Android:30分钟弄明白Touch事件分发机制

    Touch事件分发中只有两个主角:ViewGroup和View.Activity的Touch事件事实上是调用它内部的ViewGroup的Touch事件,可以直接当成ViewGroup处理. View在 ...

  6. 【转】Android:Touch事件分发机制

    Touch事件分发中只有两个主角:ViewGroup和View.Activity的Touch事件事实上是调用它内部的ViewGroup的Touch事件,可以直接当成ViewGroup处理. View在 ...

  7. Android View的事件分发机制

    准备了一阵子,一直想写一篇事件分发的文章总结一下.这个知识点实在是太重要了. 一个应用的布局是丰富的,有TextView,ImageView,Button等.这些子View的外层还有ViewGroup ...

  8. Android程序员事件分发机制学习笔记

    通过问题来学习一个东西是很好的方法.学习Android中View的事件体系,我也通过给自己提问题,在解决问题的同时也就知道了其中原理. 首先来几个问题起步: 什么是事件?什么是事件分发机制? 在我们通 ...

  9. Android view 的事件分发机制

    1 事件的传递顺序是 Activity -> Window -> 顶层View touch 事件产生后,最先由 activity 的 dispatchTouchEvent 处理 /** * ...

随机推荐

  1. MVC API 返回json 对象,使用netjson 返回

    1.清除xml 格式 GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear(); 2. ...

  2. chrome升级后出现滚动条无法滚动

    最近升级chrome最新版本后,导致项目中功能页面的局部滚动条无法滚动(心里暗骂了很久),无论怎么滚动都是最外层的滚动条响应... 1.猜想:尼玛google应该不会干事件流混乱这种事,pass: 2 ...

  3. 部署文档(centos7.x\nginx\mysql5.6\jdk1.8\ssl\jboot)

    部署文档(centos7.x\nginx\mysql5.6\jdk1.8\ssl\jboot) 1.基础环境********************************************** ...

  4. python_day13_js

    JavaScript 基础 目录: javascript简介 javascrip历史 ecmascript标准 javascrip基础 js引入方式 js变量.常量.标识符 js数据类型 运算符 流程 ...

  5. python_paramiko

    目录: paramiko模块介绍 paramiko模块安装 paramiko模块使用 一.paramiko模块介绍 paramiko是一个用于做远程控制的模块,使用该模块可以对远程服务器进行命令或文件 ...

  6. Scrum冲刺阶段1

    各个成员在 Alpha 阶段认领的任务 人员 任务 何承华 美化设计 部分后端设计 陈宇 后端设计 丁培辉 美化设计 部分后端设计 温志铭 前端设计 杨宇潇 服务器搭建 张主强 前端设计 明日各个成员 ...

  7. python抢火车票 短信通知

    # -*- coding: utf-8 -*- from splinter.browser import Browser from time import sleep import traceback ...

  8. drf2 FBV和CBV

    FBV 基于函数的视图 CBV 基于类的视图 也就是说我们是用函数编写视图~还是类编写视图 urlpatterns = [ path('admin/', admin.site.urls), path( ...

  9. 第39章:MongoDB-集群--Replica Sets(副本集)---副本集基本原理

    ①操作日志oplog Oplog是主节点的local数据库中的一个固定集合,按顺序记录了主节点的每一次写操作,MongoDB的复制功能是使用oplog来实现的,备份节点通过查询这个集合就可以知道需要进 ...

  10. 序列化与Json

    序列化: 将数据结构或对象转换成二进制串的过程. 反序列化:将在序列化过程中所生成的二进制串转换成数据结构或者对象的过程. 首先我们通过复制文件举例,这里面就包含序列化与反序列化的过程: public ...