前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >CreatorPrimer|触摸事件冒泡

CreatorPrimer|触摸事件冒泡

作者头像
张晓衡
发布2019-09-11 17:08:56
1.3K0
发布2019-09-11 17:08:56
举报

从一次微信聊天开始


前两天正在愁公众号写点什么,打开微信看到uikiller用户「悦雨」遇到了一个问题:

地图拖动与子节点触摸事件产生冲突,表现为:在子节点上拖动,但地图不动,怎么办?

一句话不太好描述问题,在征得「悦雨」同意后,将这次交流的内容截图出来:

第一话

问题描述

第二话

ScrollView解决方案

在与「悦雨」的交流过程中,我用ScrollView+TileMap+Button+AudioSource花了五分钟做了一个小测试,将TiledMap放在ScrollView中,在TiledMap中又放值了一个按钮,验证了一下曾经的经验是否任然有效。

第三话

结果是OK的,于是将测试场景发给了「悦雨」同学,但ScrollView不是想要的,继续聊这个问题:

第四话

不想用ScrollView,还有什么方案呢?触摸事件捕获!继续对话:

至此问题终于解决,下来的公众号内容也有了着落

快速原型测试


有了上面这个案例,今天就以这个地图场景为例,看看不写代码,利用引擎内置组件,如何快速实现一个原型或组件测试 ,请看下面视频:

温馨时提示:因为是在办公室录制的视频,有许多干扰的声音,视频里没有语音解说,采用的文字说明,请观看视频的时候留意文字。

从视频中可以看到,使用按钮组件,可以调用任意节点下的组件函数(无参数的),利用好这个功能,可以少写不少的代码。

从源码中学习


当知道ScrollView中拖动,不会触发子节点的事件,到此是不是就完了呢?有没想过,ScrollView它是怎么做的呢?带着好奇心,我们一起再深入一下ScrollView,它上面有一个关键属性,请看下图:

有了Cancel Inner Event这个线索,我们直接从ScrollView组件源码入手,看看它是怎么实现的。

以cc.ScrollView组件为例,看如何定位组件源码:

  1. 使用Chrome浏览器启动游戏预览
  2. 打开Chrome DevTools工具
  3. 键盘快捷键:ctrl + p 或 cmd + p
  4. 输入:ccscrollview (引擎组件原文件名公式:cc + 组件名)
  5. 从显示的列表上找到要查看的源码文件

选择CCScrollView.js文件,自动跳转到Sources标签,打开文件内容,键入ctrl + f 或 cmd + f 在当前文件中搜索:cancelInnerEvents,找到关键代码:

  1. 可以看到976行中,当 this.cancelInnerEvents变量为真可能会执行到下面的代码,设置成员变量 this._touchMoved=true
  2. 再看1006行onTouchEnd函数,在这里判断了touchMoved这个变量,停止TOUCH_END事件的传播,这样子节点的触摸事件就不会被触发了
  3. 993行onTouchMoved函数最后一行代码 this._stopPropagationIfTargetIsMe(event)它是在有条件地停止TOUCHMOVE事件的传播。

通过上面的分析,再通过断点跟踪,在ScrollView和Button组件中分别打上断点,我们在Button组件上做点击,ScrollView组件的_onTouchEnded居然先被断下来,它是怎么做到的呢?

在CCScrollView.js源码中搜“TOUCH_END”关键字,找到TOUCH事件注册的代码:

看看这里有与自己平时注册TOUCH事件有什么不同?相信你已经发现了,关键在最后一个参数:useCapture,用于是否捕获子节点事件,又称之为向下冒泡(默认是向上冒泡),下面以TOUC_END事件为例,简单说明一下:

代码语言:javascript
复制
this.node.on(
  cc.Node.EventType.TOUCH_END,   //触摸事件类型
  this._onTouchEnded,            //事件处理函数
  this,                          //事件处理函数的this上下文(使用箭头函数时通常被省略)
  true                           //是否捕获子节点Touch事件
);

为了帮助大家更好地理解,我做了个简单的小组件,请看代码:

代码语言:javascript
复制
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需要大家的大家的支持和帮助!


本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-12-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Creator星球游戏开发社区 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 从一次微信聊天开始
  • 第一话
  • 第二话
  • 第三话
  • 第四话
  • 快速原型测试
  • 从源码中学习
  • 题外话
相关产品与服务
命令行工具
腾讯云命令行工具 TCCLI 是管理腾讯云资源的统一工具。使用腾讯云命令行工具,您可以快速调用腾讯云 API 来管理您的腾讯云资源。此外,您还可以基于腾讯云的命令行工具来做自动化和脚本处理,以更多样的方式进行组合和重用。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档