Cocos2d-x 学习笔记(16) 触摸事件与分发 EventTouch dispatchTouchEvent EventListenerTouch
1. EventTouch
触摸事件的成员变量:枚举EventCode、存储Touch的容器。
不同的EventCode代表不同时机的触摸事件,能让监听器调用不同的回调函数。
enum class EventCode
{
BEGAN,
MOVED,
ENDED,
CANCELLED
};
static const int MAX_TOUCHES = 15;
EventCode _eventCode;
std::vector<Touch*> _touches;
这里涉及到了Touch类:
Touch类
封装了一个触摸信息,包括触摸点类型(单点/多点)、坐标、开始坐标、ID、3D触控压力等。有set get方法。
2. EventListenerTouch
触摸事件监听器根据触摸点touch类型的不同,分为单点触摸监听器/多点触摸监听器。
2.1 EventListenerTouchOneByOne
单点触摸监听器回调函数只能处理触摸事件中一个touch。
ID统一为:
const std::string EventListenerTouchOneByOne::LISTENER_ID = "__cc_touch_one_by_one";
该类4个回调函数,根据触摸事件code不同分类:
public:
typedef std::function<bool(Touch*, Event*)> ccTouchBeganCallback;
typedef std::function<void(Touch*, Event*)> ccTouchCallback;
ccTouchBeganCallback onTouchBegan; //开始触摸
ccTouchCallback onTouchMoved; //触摸并移动
ccTouchCallback onTouchEnded; //结束触摸
ccTouchCallback onTouchCancelled; //触摸取消
该类2个成员变量:
private:
std::vector<Touch*> _claimedTouches; //存储处理完BEGAN事件的回调函数的参数touch
bool _needSwallow; //事件需要吞没,为true时停止事件向其他监听器分发,setSwallowTouches(bool)设置,默认为false
在add监听器到分发器时,首先需要对该监听器执行checkAvailable()。单点触摸监听器的checkAvailable()中,要求onTouchBegan需要存在。
2.2 EventListenerTouchAllAtOnce
多点触摸监听器回调函数能一次处理事件中所有touch。
ID为:
const std::string EventListenerTouchAllAtOnce::LISTENER_ID = "__cc_touch_all_at_once";
4个回调函数:
public:
typedef std::function<void(const std::vector<Touch*>&, Event*)> ccTouchesCallback;
ccTouchesCallback onTouchesBegan;
ccTouchesCallback onTouchesMoved;
ccTouchesCallback onTouchesEnded;
ccTouchesCallback onTouchesCancelled;
checkAvailable()方法要求4个回调函数都要存在。
3. dispatchTouchEvent
在dispatchEvent方法中,当参数事件为TOUCH类型,调用dispatchTouchEvent进行事件分发。
该方法首先对2个触摸监听器ID的容器Vector按优先级排序,之后获取触摸事件中所有touch,用容器保存:

如果2种监听器都存在,isNeedsMutableSet置true。
然后对单点触摸监听器分发事件
单点触摸事件分发的逻辑是,把触摸事件的每个touch依次传给所有排好序的单点触摸监听器,监听器执行定义的匿名函数,而不是监听器自带的_onEvent(单点触摸监听器init时_onEvent置nullptr)。

每个单点触摸监听器执行的回调函数运行流程大致如下:
简而言之,根据触摸事件code决定执行哪种回调函数,开始触摸对应的回调函数处理touch,对处理好的touch存储到监听器容器,以便还是该监听器执行后续的移动触摸/结束触摸的回调。移动触摸对应的回调函数处理touch。结束触摸对应回调函数处理touch,并从监听器touch容器删除开始触摸的touch,说明整个触摸流程结束了。

我们知道,当某个监听器的回调函数返回true时,事件将停止分发到后续监听器。
在单点触摸的监听器中,回调函数返回true时有2个情况:触摸事件停止/触摸事件被回调函数处理完成+已注册+监听器设置true吞没标志。
在单点触摸的监听器中,回调函数返回false时有这些情况:开始触摸的回调函数没有处理完事件/监听器对开始触摸没有回调方法/移动或结束触摸事件分发到无(对应的)开始触摸数据的监听器。
当事件停止,会直接退出当前分发,结束分发。
接下来对多点触摸监听器分发事件
多点触摸事件分发的逻辑是,每个需要多点触摸的touch已经存储在容器mutableTouches中,容器传给所有排好序的多点触摸监听器,监听器执行定义的匿名函数,而不是监听器自带的_onEvent(多点触摸监听器init时_onEvent置nullptr)。
单点触摸是将每个touch依次分发到所有监听器,多点触摸是将所有touch分发到所有监听器。
分发到事件的多点触摸监听器的匿名回调函数:通过对触摸事件code的判断,决定要执行自己监听器的哪个回调函数。当事件停止返回true,停止后续监听器接收事件。
4. 触摸事件分发时的Touch*容器 originalTouches mutableTouches
两个容器开始时都存储了本触摸事件的所有touch。
事件分发到单点触摸监听器,是遍历originalTouches,获取每个touch,再分发touch到监听器。
单点触摸回调函数中,如果一个touch在某个单点触摸监听器中处理完成,且_needSwallow为true,且存在多点触摸监听器,此时要从mutableTouches删除该touch。原因是_needSwallow为true说明本touch处理完后不再继续分发,而mutableTouches是需要分发到多点触摸监听器,故从mutableTouches中删除该touch。mutableTouches中的迭代器自动指向下一位。同时isSwallowed置true,即不用执行++mutableTouchesIter,迭代器已经实现了++操作。
还是上面的情况,如果没有多点触摸监听器,isSwallowed默认false,匿名回调函数返回true,停止本touch分发。接下来执行++mutableTouchesIter,和originalTouches一致。
简而言之,mutableTouches只在有多点触摸监听器的情况下可能发挥它独特的作用(只保存需要接下来多点触发的touch),否则和originalTouches无异,只是存储所有touch而已。
if (isClaimed && listener->_isRegistered && listener->_needSwallow) //如果事件处理完成,监听器注册状态, 监听器吞没
{
if (isNeedsMutableSet) //单点多点触摸的监听器都有
{
mutableTouchesIter = mutableTouches.erase(mutableTouchesIter); //删除此触摸点信息
isSwallowed = true; //
}
return true;
}
if (!isSwallowed)
++mutableTouchesIter;
//接下来遍历下个touch
Cocos2d-x 学习笔记(16) 触摸事件与分发 EventTouch dispatchTouchEvent EventListenerTouch的更多相关文章
- iOS学习笔记之触摸事件&UIResponder
iOS学习笔记之触摸事件&UIResponder 触摸事件 与触摸事件相关的四个方法如下: 一根手指或多根手指触摸屏幕 -(void)touchesBegan:(NSSet *)touches ...
- Ext.Net学习笔记16:Ext.Net GridPanel 折叠/展开行
Ext.Net学习笔记16:Ext.Net GridPanel 折叠/展开行 Ext.Net GridPanel的行支持折叠/展开功能,这个功能个人觉得还说很有用处的,尤其是数据中包含图片等内容的时候 ...
- SQL反模式学习笔记16 使用随机数排序
目标:随机排序,使用高效的SQL语句查询获取随机数据样本. 反模式:使用RAND()随机函数 SELECT * FROM Employees AS e ORDER BY RAND() Limit 1 ...
- golang学习笔记16 beego orm 数据库操作
golang学习笔记16 beego orm 数据库操作 beego ORM 是一个强大的 Go 语言 ORM 框架.她的灵感主要来自 Django ORM 和 SQLAlchemy. 目前该框架仍处 ...
- 一个demo让你彻底理解Android中触摸事件的分发
注:本文涉及的demo的地址:https://github.com/absfree/TouchDispatch 1. 触摸动作及事件序列 (1)触摸事件的动作 触摸动作一共有三种:ACTION_DOW ...
- Android学习笔记点击事件和触摸事件的区别
当我们点击手机屏幕的时候Android系统不仅会触发单击事件,还会触发触摸事件.在Android中它会先触发触摸事件,如果这个触摸事件没有被消费掉再去触发单击事件 代码示例: MainActivty. ...
- iOS学习笔记07-运动事件和远程控制
之前我们已经学习了触摸处理和手势识别,其实这两个同属于iOS事件的触摸事件,今天我们来学习下iOS事件的另外两个事件: 一.运动事件 运动事件,是通过加速器进行触发,和触摸事件一样,继承UIRespo ...
- 微信小程序学习笔记二 数据绑定 + 事件绑定
微信小程序学习笔记二 1. 小程序特点概述 没有DOM 组件化开发: 具备特定功能效果的代码集合 体积小, 单个压缩包体积不能大于2M, 否则无法上线 小程序的四个重要的文件 *js *.wxml - ...
- AngularJS1.X学习笔记4-内置事件指令及其他
AngularJS为我们定义了一系列事件指令,方便我们对用户的操作作出响应.甚至他还有一个可选模块提供了触摸事件和手势事件的支持,为移动端开发提供了可能.现在开始学习一下AngularJS的事件指令. ...
随机推荐
- valueForKey与valueForKeyPath 区别
1.删除数组中重复的数据 2.valueForKeyPath:可以深层次取到子属性,不管隐藏的多深 valueForKey:无法取到深层次子属性 但是也有其相似的地方: 比如:快速找到字典数组中ke ...
- STL中排序函数的用法(Qsort,Sort,Stable_sort,Partial_sort,List::sort)
都知道排序很重要,也学了各式各样的排序算法,冒泡.插入.归并等等,但其实在ACM比赛中,只要不是太慢的算法,都可以适用(除非某些题目卡时间卡的很死),这个时候,速度与技巧便成了关键,而在C++的标准库 ...
- linux 假死分析
所谓假死,就是能ping通,但是ssh不上去:任何其他操作也都没反应,包括上面部署的apache也打不开页面. 作为一个多任务操作系统,要把系统忙死,忙到ssh都连不上去,也不是那么容易的.尤其是现在 ...
- App引流增长技术:Deeplink(深度链接)技术
移动互联网时代,信息的分享传播无疑是 App 引流增长的关键,与其花费大量精力和成本找渠道.硬推广,不如从细节下手,用最快最简便的方法实现 Deeplink(深度链接)技术,打破信息孤岛.缩短分享路径 ...
- rpm方式升级cenos6.7内核
最近因为yarn集群问题需要配置cgroup.但是配置完成后操作系统内核奔溃. 查找资料后发现升级内核可以解决问题.在领导的大力支持下,对生产环境的计算节点(nodemanager)进行了批量升级内核 ...
- Spring boot 梳理 - WebMvcConfigurer接口 使用案例
转:https://yq.aliyun.com/articles/617307 SpringBoot 确实为我们做了很多事情, 但有时候我们想要自己定义一些Handler,Interceptor,Vi ...
- mybatis-dynamic-query 3.0 更新
项目地址: mybatis-dynamic-query 前言 在 2.0 完成对 tk.mapper 集成,为何 mybatis-dynamic-query 选择 tk.mapper 集成, 再 3. ...
- RBD 基本使用 - Storage6
块存储管理系列文章 (1)RBD 基本使用 - Storage6 (2)iSCSI 网关管理 (3)使用 librbd 将虚拟机运行在 Ceph RBD (4)RBD Mirror 容灾 Ceph 块 ...
- forEach标签
1.forEach标签的简单使用: (1)未设置步长属性时,默认步长为1: <c:forEach "> <c:out value="${number}" ...
- 文本数据IO操作--字符流
一.Reader和Writer 1. 字符流原理 Reader是所有字符输入流的父类而Writer是所有字符输出流的父类.字符流是以字符(char)为单位读写数据的.一次处理一个unicode.字符流 ...