内容简介:事件分发流程对于我们开发者来讲,有什么作用?引用官方介绍:Object used to report movement (mouse, pen, finger, trackball) events. Motion events may hold either absolute or relative movements and other data, depending on the type of device.大致意思就是用于报告移动(鼠标,笔,手指,轨迹球)事件的对象。运动事件可以保持绝对或相对运动以
作用
事件分发流程对于我们开发者来讲,有什么作用?
- 根据我们自己的需求来自定义滑动触摸响应的规则。
- 解决滑动冲突
相关知识
MotionEvent
引用官方介绍:Object used to report movement (mouse, pen, finger, trackball) events. Motion events may hold either absolute or relative movements and other data, depending on the type of device.
大致意思就是用于报告移动(鼠标,笔,手指,轨迹球)事件的对象。运动事件可以保持绝对或相对运动以及其他数据,具体取决于设备的类型。
在事件分发中,典型常用的事件总共有三个:
- ACTION_DOWN ------按下操作
- ACTION_MOVE -------移动操作
- ACTION_UP -----------抬起操作
一般一个事件的完整流程是 ACTION_DOWN ---> ACTION_MOVE ---> ACTION_UP
常用方法 | 含义 |
---|---|
getX/Y() | 点击事件相对于 当前 View 左上角 的 x/y 轴距离 |
getRawX/Y() | 点击事件相对于 手机屏幕左上角 的 x/y 轴距离 |
事件分发相关方法。
-
public boolean dispatchTouchEvent(MotionEvent ev)
用于事件分发,将触摸事件向下传递给目标视图,如果它本身就是目标视图,则传递给自己来处理事件。返回结果受自己的 onTouchEvent 和下级 View 的 dispatchTouchEvent 方法影响。
-
public boolean onInterceptTouchEvent(MotionEvent ev)
在 dispatchTouchEvent 中调用。是否进行事件拦截,如果返回 false ,则代表不拦截事件;如果返回事件为 true,则拦截事件,并且此事件的后续事件都交给自己来处理,不会再调用此方法询问是否拦截。
只有 ViewGroup 有这个方法,默认返回 false,不拦截。
-
public boolean onTouchEvent(MotionEvent ev)
在 dispatchTouchEvent 中调用。用来处理事件,返回 true 代表消费事件 ;返回 false 代表不消费事件 。
代表三者关系的 伪代码 :(摘抄于《Android艺术开发探索》第三章)
//伪代码,解释 dispatchTouchEvent 和 onInterceptTouchEvent 以及 onTouchEvent 的调用关系 public boolean dispatchTouchEvent(MotionEvent ev){ boolean consume; if(onInterceptTouchEvent(ev)){ consume = onTouchEvent(ev); }else{ consume = childView.dispatchTouchEvent(ev); } return consume ; } 复制代码
通过上面的伪代码,我们可以大致的了解事件的传递规则: 对于一个根 ViewGroup 来说,点击事件产生后,首先会传递给它,这时它的 dispatchTouchEvent 就会被调用,如果它的 onInterceptTouchEvent 方法返回 true,就表示要拦截事件,接着事件就交给这个 ViewGroup 的 onTouchEvent 来处理,如果 onInterceptTouchEvent 返回 false,表示不拦截事件,当前事件就会传递给它的子元素,接着子元素的 dispatchTouchEvent 方法就会被调用,如此反复直到事件被最终处理。
分发流程
三个方法在具体项目中的具体的调用流程是什么呢?我们用个 Demo 来演示。
都只是简单 重写这三个方法 ,并打印日志。
public class Group1 extends FrameLayout { public static final String TAG = "----------"; //......代码省略...... @Override public boolean dispatchTouchEvent(MotionEvent ev) { Log.i(TAG, "dispatchTouchEvent-----------------"+ Util.getMotionEvent(ev) + this.getClass().getSimpleName()); return super.dispatchTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { Log.i(TAG, "onInterceptTouchEvent-----------------" + Util.getMotionEvent(ev)+ this.getClass().getSimpleName()); return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { Log.i(TAG, "onTouchEvent-----------------" + Util.getMotionEvent(event)+ this.getClass().getSimpleName()); return super.onTouchEvent(event); } } 复制代码
View 的代码:
public class View1 extends View { public static final String TAG = "----------"; //......代码省略...... @Override public boolean dispatchTouchEvent(MotionEvent event) { Log.i(TAG,"dispatchTouchEvent-----------------" + Util.getMotionEvent(event)+ this.getClass().getSimpleName()); return super.dispatchTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { Log.i(TAG,"onTouchEvent-----------------"+ Util.getMotionEvent(event) + this.getClass().getSimpleName()); return super.onTouchEvent(event); } } 复制代码
Util 类代码(打印出事件的名称):
class Util { static String getMotionEvent(MotionEvent motionEvent) { int action = motionEvent.getAction(); if (action == MotionEvent.ACTION_DOWN) { return "ACTION_DOWN----"; } else if (action == MotionEvent.ACTION_UP) { return "ACTION_UP------"; } else if (action == MotionEvent.ACTION_MOVE) { return "ACTION_MOVE----"; } else if (action == MotionEvent.ACTION_CANCEL) { return "ACTION_CANCEL--"; } else { return String.valueOf(motionEvent); } } } 复制代码
MainActivity的代码:
public class MainActivity extends AppCompatActivity { public static final String TAG = "----------"; //......代码省略...... @Override public boolean dispatchTouchEvent(MotionEvent ev) { Log.i(TAG, "dispatchTouchEvent-----------------" + com.sjc.eventdispatch.Util.getMotionEvent(ev) + this.getClass().getSimpleName()); return super.dispatchTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { Log.i(TAG, "onTouchEvent-----------------" + com.sjc.eventdispatch.Util.getMotionEvent(event) + this.getClass().getSimpleName()); return super.onTouchEvent(event); } } 复制代码
MainActivity中的 xml 文件:
<?xml version="1.0" encoding="utf-8"?> <com.sjc.eventdispatch.Group1 xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <com.sjc.eventdispatch.View1 android:id="@+id/view1" android:layout_width="200dp" android:layout_height="300dp" android:layout_gravity="center" android:background="@color/colorPrimaryDark" /> </com.sjc.eventdispatch.Group1> 复制代码
具体页面呈现:
模拟一:- 条件:所有方法都保持返回 super.xxx(event) 状态;
- 动作:点击 View1 ;
//Log日志 ----------: dispatchTouchEvent--------ACTION_DOWN----MainActivity ----------: dispatchTouchEvent--------ACTION_DOWN----Group1 ----------: onInterceptTouchEvent--------ACTION_DOWN----Group1 ----------: dispatchTouchEvent--------ACTION_DOWN----View1 ----------: onTouchEvent--------ACTION_DOWN----View1 ----------: onTouchEvent--------ACTION_DOWN----Group1 ----------: onTouchEvent--------ACTION_DOWN----MainActivity ----------: dispatchTouchEvent--------ACTION_MOVE----MainActivity ----------: onTouchEvent--------ACTION_MOVE----MainActivity ----------: dispatchTouchEvent--------ACTION_UP------MainActivity ----------: onTouchEvent--------ACTION_UP------MainActivity 复制代码
从事件的传递过程,我们可以看出,当用户触摸屏幕进行操作时,事件先传递给 Activity,然后通过 dispatchTouchEvent
分发给跟布局 Group1 ,Group1 进行事件分发,先进行调用自己的 onInterceptTouchEvent
进行询问是否拦截(默认不拦截),然后就传递给当前点击的子控件 View1,View1 通过自己的 dispatchTouchEvent
方法分发给自己,调用自己的 onTouchEvent
方法。View1 默认不消费事件,事件就传递给了Group1 自己的 onTouchEvent 方法,由于 Group1 也不消费事件,事件就回传给了 Activity,最终 Activity 的 onTouchEvent 接收了事件,并且后续事件也是由它直接接收。
结论:
- 如果一个控件不消费传递过来的 DOWN 事件,那么后续事件不会传递给它。
- 如果一个点击区域的所有控件都不消费事件,那么这个事件最终会传递个 Activity 。
模拟二:
- 条件:View1 的 onTouchEvent 方法返回 true ;
- 动作:点击 View1 ;
//log日志 ----------: dispatchTouchEvent--------ACTION_DOWN----MainActivity ----------: dispatchTouchEvent--------ACTION_DOWN----Group1 ----------: onInterceptTouchEvent--------ACTION_DOWN----Group1 ----------: dispatchTouchEvent--------ACTION_DOWN----View1 ----------: onTouchEvent--------ACTION_DOWN----View1 ----------: dispatchTouchEvent--------ACTION_MOVE----MainActivity ----------: dispatchTouchEvent--------ACTION_MOVE----Group1 ----------: onInterceptTouchEvent--------ACTION_MOVE----Group1 ----------: dispatchTouchEvent--------ACTION_MOVE----View1 ----------: onTouchEvent--------ACTION_MOVE----View1 ----------: dispatchTouchEvent--------ACTION_UP------MainActivity ----------: dispatchTouchEvent--------ACTION_UP------Group1 ----------: onInterceptTouchEvent--------ACTION_UP------Group1 ----------: dispatchTouchEvent--------ACTION_UP------View1 ----------: onTouchEvent--------ACTION_UP------View1 复制代码
典型的点击事件传递过程,用户点击一个按钮,按钮来响应操作,事件被这个按钮消费。并且每次事件传递过来时,Group1 都会调用 onInterceptTouchEvent 方法来进行检查是否拦截。
模拟三:
- 条件1:View1 的 onTouchEvent 方法返回 true, Group1 的 onInterceptTouchEvent 返回 true 。
- 动作1:点击 View1 ;
//Log日志 ----------: dispatchTouchEvent--------ACTION_DOWN----MainActivity ----------: dispatchTouchEvent--------ACTION_DOWN----Group1 ----------: onInterceptTouchEvent--------ACTION_DOWN----Group1 ----------: onTouchEvent--------ACTION_DOWN----Group1 ----------: onTouchEvent--------ACTION_DOWN----MainActivity ----------: dispatchTouchEvent--------ACTION_MOVE----MainActivity ----------: onTouchEvent--------ACTION_MOVE----MainActivity ----------: dispatchTouchEvent--------ACTION_UP------MainActivity ----------: onTouchEvent--------ACTION_UP------MainActivity 复制代码
- 条件2:View1 的 onTouchEvent 方法返回 true ,Group1 的 onInterceptTouchEvent 返回 true ,Group1 的 onTouchEvent 返回 true 。
- 动作2:点击 View1 。
//Log日志 ----------: dispatchTouchEvent--------ACTION_DOWN----MainActivity ----------: dispatchTouchEvent--------ACTION_DOWN----Group1 ----------: onInterceptTouchEvent--------ACTION_DOWN----Group1 ----------: onTouchEvent--------ACTION_DOWN----Group1 ----------: dispatchTouchEvent--------ACTION_MOVE----MainActivity ----------: dispatchTouchEvent--------ACTION_MOVE----Group1 ----------: onTouchEvent--------ACTION_MOVE----Group1 ----------: dispatchTouchEvent--------ACTION_UP------MainActivity ----------: dispatchTouchEvent--------ACTION_UP------Group1 ----------: onTouchEvent--------ACTION_UP------Group1 复制代码
Group1 的 onInterceptTouchEvent 返回 true 拦截事件,它的 onTouchEvent 被调用。onTouchEvent 返回 true 代表事件被消费,后续事件都传递给它来处理;onTouchEvent 返回 false 代表事件没有消费,事件向上传递给 Activity ,后续事件都不会传递给 Group1 和 View1 来处理。
结论:
如果一个控件不消费传递过来的 DOWN 事件,那么后续事件不会传递给它
总结
其他知识点:
CANCEL 事件的理解
事件序列的非人为的提前结束。
模拟条件:
- View1 的 onTouchEvent 方法返回 true ;
- Group1 的 onInterceptTouchEvent 在 MOVE 事件上返回 true,其他事件返回false。
- 其他方法保持返回 super.xxx()。
模拟动作:点击 View1 ;
public class Group1 extends FrameLayout { public static final String TAG = "----------"; //......代码省略...... @Override public boolean onInterceptTouchEvent(MotionEvent ev) { Log.i(TAG, "onInterceptTouchEvent--------" + Util.getMotionEvent(ev) + this.getClass().getSimpleName()); boolean intercept; switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: intercept = false; break; case MotionEvent.ACTION_MOVE: intercept = true; break; case MotionEvent.ACTION_UP: intercept = false; break; default: intercept = false; break; } return intercept; } } 复制代码
//log日志 ----------: dispatchTouchEvent--------ACTION_DOWN----MainActivity ----------: dispatchTouchEvent--------ACTION_DOWN----Group1 ----------: onInterceptTouchEvent--------ACTION_DOWN----Group1 ----------: dispatchTouchEvent--------ACTION_DOWN----View1 ----------: onTouchEvent--------ACTION_DOWN----View1 ----------: dispatchTouchEvent--------ACTION_MOVE----MainActivity ----------: dispatchTouchEvent--------ACTION_MOVE----Group1 ----------: onInterceptTouchEvent--------ACTION_MOVE----Group1 ----------: dispatchTouchEvent--------ACTION_CANCEL--View1 ----------: onTouchEvent--------ACTION_CANCEL--View1 ----------: dispatchTouchEvent--------ACTION_MOVE----MainActivity ----------: dispatchTouchEvent--------ACTION_MOVE----Group1 ----------: onTouchEvent--------ACTION_MOVE----Group1 ----------: onTouchEvent--------ACTION_MOVE----MainActivity ----------: dispatchTouchEvent--------ACTION_UP------MainActivity ----------: dispatchTouchEvent--------ACTION_UP------Group1 ----------: onTouchEvent--------ACTION_UP------Group1 ----------: onTouchEvent--------ACTION_UP------MainActivity 复制代码
在这个事件流中,View1 首先消费了 DOWN 事件。当用户移动,产生了 MOVE 事件,由于 Group1 的 onInterceptTouchEvent 方法在 MOVE 事件中返回 true,表示开始拦截事件,MOVE 事件及后面的 UP 事件都交给 Group 1处理,不再传递给 View1。而此时 View1 只消费了 DOWN 事件,处于一个事件流的中途阶段,为了让 View1 有一个完整的事件流,就传递给 View1 一个 CANCEL 事件,从而告诉 View1 这个事件流对于它来说已经结束了。
requestDisallowInterceptTouchEvent
请求父控件不要拦截事件。属于 ViewParent 的方法,ViewParent是一个接口,ViewGroup 实现了 ViewParent 接口。
模拟条件:
- View1 的 onTouchEvent 方法返回 true ,在 dispatchTouchEvent 方法中调用 requestDisallowInterceptTouchEvent 方法;
- Group1 的 onInterceptTouchEvent 在 MOVE 事件上返回 true,其他事件返回false。
- 其他方法保持返回 super.xxx()。
模拟动作:点击 View1 ;
public class View1 extends View { public static final String TAG = "----------"; //......代码省略...... @Override public boolean dispatchTouchEvent(MotionEvent event) { Log.i(TAG, "dispatchTouchEvent--------" + Util.getMotionEvent(event) + this.getClass().getSimpleName()); getParent().requestDisallowInterceptTouchEvent(true); return super.dispatchTouchEvent(event); } } 复制代码
----------: dispatchTouchEvent--------ACTION_DOWN----MainActivity ----------: dispatchTouchEvent--------ACTION_DOWN----Group1 ----------: onInterceptTouchEvent--------ACTION_DOWN----Group1 ----------: dispatchTouchEvent--------ACTION_DOWN----View1 ----------: onTouchEvent--------ACTION_DOWN----View1 ----------: dispatchTouchEvent--------ACTION_MOVE----MainActivity ----------: dispatchTouchEvent--------ACTION_MOVE----Group1 ----------: dispatchTouchEvent--------ACTION_MOVE----View1 ----------: onTouchEvent--------ACTION_MOVE----View1 ----------: dispatchTouchEvent--------ACTION_UP------MainActivity ----------: dispatchTouchEvent--------ACTION_UP------Group1 ----------: onInterceptTouchEvent--------ACTION_UP------Group1 ----------: dispatchTouchEvent--------ACTION_UP------View1 ----------: onTouchEvent--------ACTION_UP------View1 复制代码
我们可以看到 View1 调用 requestDisallowInterceptTouchEvent 后,能够接收到 MOVE 事件以及后续其他事件,Group1 的拦截并没有起作用。从而我们可以使用 requestDisallowInterceptTouchEvent 来解决一些开发商的滑动冲突之类的问题。
注意:View 调用 requestDisallowInterceptTouchEvent 请求父控件不拦截生效有意义的前提是: View接收到了 DOWN 事件,并且消费了 DOWN 事件。如果一个控件不消费 DOWN 事件,那么后续事件也不会传递给它。
以上所述就是小编给大家介绍的《View的事件分发(一)分发流程》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Android Binder,AIDL使用流程及进程之间的事件分发
- Android事件分发机制
- OSPF路由重分发
- 【Leetcode】135.分发糖果
- View事件分发机制分析
- 【透镜系列】看穿 > 触摸事件分发
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Python高级编程(第二版)
[波兰] Michał Jaworski、[法] Tarek Ziadé / 张亮、阿信 / 人民邮电出版社 / 2017-9-19 / 89.00元
Python作为一种高级程序设计语言,凭借其简洁、易读及可扩展性日渐成为程序设计领域备受推崇的语言之一。 本书基于Python 3.5版本进行讲解,通过13章的内容,深度揭示了Python编程的高级技巧。本书从Python语言及其社区的现状开始介绍,对Python语法、命名规则、Python包的编写、部署代码、扩展程序开发、管理代码、文档编写、测试开发、代码优化、并发编程、设计模式等重要话题......一起来看看 《Python高级编程(第二版)》 这本书的介绍吧!