CreatorPrimer|触摸事件冒泡
从一次微信聊天开始
前两天正在愁公众号写点什么,打开微信看到uikiller用户「悦雨」遇到了一个问题:
地图拖动与子节点触摸事件产生冲突,表现为:在子节点上拖动,但地图不动,怎么办?
一句话不太好描述问题,在征得「悦雨」同意后,将这次交流的内容截图出来:
第一话
问题描述
第二话
ScrollView解决方案
在与「悦雨」的交流过程中,我用ScrollView+TileMap+Button+AudioSource花了五分钟做了一个小测试,将TiledMap放在ScrollView中,在TiledMap中又放值了一个按钮,验证了一下曾经的经验是否任然有效。
第三话
结果是OK的,于是将测试场景发给了「悦雨」同学,但ScrollView不是想要的,继续聊这个问题:
第四话
不想用ScrollView,还有什么方案呢?触摸事件捕获!继续对话:
至此问题终于解决,下来的公众号内容也有了着落
快速原型测试
有了上面这个案例,今天就以这个地图场景为例,看看不写代码,利用引擎内置组件,如何快速实现一个原型或组件测试 ,请看下面视频:
温馨时提示:因为是在办公室录制的视频,有许多干扰的声音,视频里没有语音解说,采用的文字说明,请观看视频的时候留意文字。
从视频中可以看到,使用按钮组件,可以调用任意节点下的组件函数(无参数的),利用好这个功能,可以少写不少的代码。
从源码中学习
当知道ScrollView中拖动,不会触发子节点的事件,到此是不是就完了呢?有没想过,ScrollView它是怎么做的呢?带着好奇心,我们一起再深入一下ScrollView,它上面有一个关键属性,请看下图:
有了Cancel Inner Event这个线索,我们直接从ScrollView组件源码入手,看看它是怎么实现的。
以cc.ScrollView组件为例,看如何定位组件源码:
使用Chrome浏览器启动游戏预览
打开Chrome DevTools工具
键盘快捷键:ctrl + p 或 cmd + p
输入:ccscrollview (引擎组件原文件名公式:cc + 组件名)
从显示的列表上找到要查看的源码文件
选择CCScrollView.js文件,自动跳转到Sources标签,打开文件内容,键入ctrl + f 或 cmd + f 在当前文件中搜索:cancelInnerEvents,找到关键代码:
可以看到976行中,当
this.cancelInnerEvents
变量为真可能会执行到下面的代码,设置成员变量this._touchMoved=true
再看1006行onTouchEnd函数,在这里判断了touchMoved这个变量,停止TOUCH_END事件的传播,这样子节点的触摸事件就不会被触发了
993行onTouchMoved函数最后一行代码
this._stopPropagationIfTargetIsMe(event)
它是在有条件地停止TOUCHMOVE事件的传播。
通过上面的分析,再通过断点跟踪,在ScrollView和Button组件中分别打上断点,我们在Button组件上做点击,ScrollView组件的_onTouchEnded居然先被断下来,它是怎么做到的呢?
在CCScrollView.js源码中搜“TOUCH_END”关键字,找到TOUCH事件注册的代码:
看看这里有与自己平时注册TOUCH事件有什么不同?相信你已经发现了,关键在最后一个参数:useCapture,用于是否捕获子节点事件,又称之为向下冒泡(默认是向上冒泡),下面以TOUC_END事件为例,简单说明一下:
this.node.on(
cc.Node.EventType.TOUCH_END, //触摸事件类型
this._onTouchEnded, //事件处理函数
this, //事件处理函数的this上下文(使用箭头函数时通常被省略)
true //是否捕获子节点Touch事件
);
为了帮助大家更好地理解,我做了个简单的小组件,请看代码:
cc.Class({
extends: cc.Component,
properties: {
useCapture: false, //是否启用捕获
},
onLoad () {
this.node.on(
cc.Node.EventType.TOUCH_END,
() => cc.log('touchend', this.node.name), //测试时观察日志输入出
this,
this.useCapture
);
}
});
把这个组件挂到两个父子关系的节点上,在父节点上开启捕获,看下面截图:
运行点击红色节点,看看日志输出:
从日志中看到白色节点先响应,然后是红色节点,我们把白色父节点的UseCapture关闭,再看看日志输出:
这次是红色子节点先响应,白色父节点后响应,更多细节可以参考Cocos Creator官方文档:
https://docs.cocos.com/creator/manual/zh/scripting/internal-events.html?h=%E5%86%92%E6%B3%A1
还有对应的官方范例:TouchPropagation
题外话
这次除了教程,还想再聊一个事情,经常会有同学通过微信、QQ、公众号向Shawn咨询问题,首先感谢大家对shawn的信任,如果是在自己的能力范围内且对大家帮助的内容,Shawn一定真诚对待,这也正是「奎特尔星球」内容的重要来源。但是因为个人能力和时间有限,不是每一个人的问题Shawn都能解答,还望大家见谅。
微信、QQ很容易让人在工作时分心,一般在做事的时候会将手机静音或离远一点,公众号上偶尔也收有留言,但有时会忘记去公众号上查看,超过24小时的留言,看到了想回复也无没办法,很是无奈。
为了能把公众号做好,Shawn特地定制了一个域名:creator-star.cn以及专用邮箱:shawn@creator-star.cn,欢迎大家向公众号投稿和讨论问题,Shawn需要大家的大家的支持和帮助!
欢迎关注「奎特尔星球」微信公众号,
「奎特尔星球」微信公众号
「奎特尔星球」博客网站,建设中...