问题情境

模拟一个类似游戏提示信息的层:

1.游戏主场景可触摸,可交互;

2.当提示显示提示信息时,只有提示信息这一层可触摸同用户交互,其背景则不能继续响应触摸事件

3.当提示信息层从主场景中移除之后,游戏主场景才能继续响应触摸事件进行交互。

这里,我们暂时把“提示信息层”称为SwallowTouchLayer;将游戏主场景曾称为GameLayer

进一步描述上述情景的实质问题:

添加一个层“吃掉”(swallow)原有层touch事件

1.SwallowTouchLayer必须swallowTouches = YES;

2.SwallowTouchLayer的触摸事件优先级 > GameLayer的触摸事件优先级

为了解决上述问题,我们首先要了解cocos-2d中触摸事件的分发机制,问题解决就明了了。

这里以HellowWorld为例,在HellowWorld之上添加一个SwallowTouchLayer

参照下图

代码实现

1.首先在HellowWorldLayer.m中添加一个新的按钮项

CCMenuItem *addSwallowTouchLayerItem = [CCMenuItemFontitemWithString:@"addSwallowTouchLayer"block:^(id sender){

[selfaddChild:[[SwallowTouchLayeralloc]init]];

}];

CCMenu *menu = [CCMenumenuWithItems:itemAchievement, itemLeaderboard,addSwallowTouchLayerItem,nil];


2.实现SwallowTouchLayer

SwallowTouchLayer.h

#import<Foundation/Foundation.h>

#import"cocos2d.h"

@interface SwallowTouchLayer :CCLayer

{

CCSprite *grayBackground;

CCMenu *menu;

}

@end

SwallowTouchLayer.m

//

//  SwallowTouchLayer.m

//  SwallowTouch

//

#import"SwallowTouchLayer.h"

@implementation SwallowTouchLayer

- (id)init

{

if(self = [super init])

{

//开启接收触摸事件

self.isTouchEnabled = YES;

//添加灰度背景

grayBackground = [CCSprite spriteWithFile:@"swallowBackground.png"];

grayBackground.position =ccp(240,160);

[self addChild:grayBackground];

//初始化Menu

CCMenuItem *menuItem = [CCMenuItemToggle itemWithTarget:self

selector:@selector(removeTeaching)

items:[CCMenuItemImage          itemWithNormalImage:@"Icon.png"                                                                                          selectedImage:nil],                                                                         [CCMenuItemImage itemWithNormalImage:@"Icon.png"                                                                                          selectedImage:nil],

nil];

//设置第一步教程的位置

menuItem.position =ccp(0,0);

menu = [CCMenu menuWithItems:menuItem,nil];

menu.position =ccp(240,160);

//添加教程

[self addChild:menu];

}

return    self;

}

- (void)onEnter

{

//在super onEnter中调用自身和孩子节点的registerWithTouchDispatcher,添加触摸代理

[super onEnter];

//重新调整menu响应优先级,使其能够响应触摸事件,视实际情况,可以省略该步

   [menu setHandlerPriority:kCCMenuHandlerPriority -2];

}

- (void)onExit

{

[[[CCDirector sharedDirector] touchDispatcher] removeDelegate:self];

[super onExit];

}

- (void)dealloc

{

[super dealloc];

}

//将自己从父场景中移除

- (void)removeTeaching

{

[self removeFromParentAndCleanup:YES];

}

#pragma mark - Swallow Touch Input

/*

*将CCLayer注册到CCTargetedTouchDelegate中,并将其响应优先级调至大于(等于)要覆盖的

*优先级对象的响应优先级

*/

- (void)registerWithTouchDispatcher

{

CCTouchDispatcher *touchDispatcher = [[CCDirector sharedDirector] touchDispatcher];

[touchDispatcher addTargetedDelegate:self

priority:kCCMenuHandlerPriority -1

swallowsTouches:YES];

}

- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event

{

//如果return NO,则不阻拦触摸消息

return    YES;

}

@end

原理解释

1.当点击HellowWorldLayer中的addSwallowTouch按钮,

[selfaddChild:[[SwallowTouchLayeralloc]init]];添加SwallowTouchLayer。

2.在init函数中

self.isTouchEnabled =YES;开启触摸事件。在此处设置断点,运行程序,跟踪一下运行实质:

2.1响应CCLayer的setIsTouchEnable消息:

-(void) setIsTouchEnabled:(BOOL)enabled

{

if( isTouchEnabled_ != enabled )

{

               isTouchEnabled_ = enabled; //这里是属性修改由NO改成了YES

if( isRunning_ )

{

if( enabled )

[self registerWithTouchDispatcher];

else

{

CCDirector *director = [CCDirector sharedDirector];

[[director touchDispatcher] removeDelegate:self];

}

}

}

}

2.2此时SwallowTouchLayer只是初始化并未添加到场景中,所以isRunnig_为NO,因此实际上在init函数中虽然self.isTouchEnabled = YES;但是只属性的修改,并没有真正将触摸事件注册到消息分发列表中(registerWithTouchDispatcher没有执行)

3.在init函数中初始化×××背景和menu按钮,为按钮添加绑定事件

selector:@selector(removeTeaching)

这里removeTeaching是将SwallowTouchLayer自身从父场景中移除掉

4.上述只是SwallowTouchLayer的初始化工作,当HellowWorld中[self addChild:...];

将SwallowTouchLayer添加到场景中,首先调用的是OnEnter();进入场景消息响应函数

5.首先[super onEnter];调用父类CCLayer的onEnter函数:

-(void) onEnter

{

#ifdef __CC_PLATFORM_IOS

// register 'parent' nodes first

// since events are propagated in reverse order

if (isTouchEnabled_)

[self registerWithTouchDispatcher]; //这个函数,我们在SwallowTouchLayer中已重写

#elif defined(__CC_PLATFORM_MAC)

CCDirector *director = [CCDirector sharedDirector];

CCEventDispatcher *eventDispatcher = [director eventDispatcher];

if( isMouseEnabled_ )

[eventDispatcher addMouseDelegate:self priority:[self mouseDelegatePriority]];

if( isKeyboardEnabled_)

[eventDispatcher addKeyboardDelegate:self priority:[self keyboardDelegatePriority]];

if( isTouchEnabled_)

[eventDispatcher addTouchDelegate:self priority:[self touchDelegatePriority]];

#endif

// then iterate over all the children

[super onEnter]; //继续找父类CCNode调用onEnter

}

详解:

(1)由于我们在init函数中已经修改了isTouchEnable为YES,所以自身调用注册触摸消息分发registerWithTouchDispatcher

我们在SwallowTouchLayer中重写了这个函数,在这个函数中

CCTouchDispatcher *touchDispatcher = [[CCDirectorsharedDirector]touchDispatcher];

[touchDispatcheraddTargetedDelegate:self

priority:kCCMenuHandlerPriority -1

swallowsTouches:YES];

绑定触摸事件代理(CCLayer默认遵守TargetedTouchDelegate),而且priority(触摸响应优先级)设置为最高(KCCMenuHandlerPriority=-128,数值越小优先级越高)

将swallowTouches设为YES,即在触摸响应层中,结束触摸事件处理,不再交予别的层继续处理。

(2)[super onEnter];找到CCNode的onEnter

-(void) onEnter

{

[children_ makeObjectsPerformSelector:@selector(onEnter)];

[self resumeSchedulerAndActions];

isRunning_ =YES;

}

让所有children响应onEnter;确认运行(isRunning_=YES);此时CCLayer的onEnter事件响应完毕

6.在4中我们只是了解了SwallowTouchLayer的onEnter中的第一步 [super onEnter];

- (void)onEnter

{

//1.super onEnter中调用自身和孩子节点的registerWithTouchDispatcher,添加触摸代理

       [superonEnter];

//2.重新调整menu响应优先级,使其能够响应触摸事件,视实际情况,可以省略该步

       [menusetHandlerPriority:kCCMenuHandlerPriority -2];//-130

}

第2步,调整触摸优先级,将menu按钮的优先级跳到最高

还记得我们在[super onEnter];中调用SwallowTouchLayer的registerWithTouchDispacher;我们将SwallowTouchLayer自身的响应优先级设置为kCCMenuHandlerPriority -1;(-129)

所以,在Cocos-2d中触摸优先级响应最高时-128;而我们将SwallowTouchLayer的优先级设为-129,又将menu的优先级设为了-130;

而menu默认SwallowTouch=YES;我们在SwallowTouchLayer的registerWithTouchDispacher;函数中同样设置了SwallowTouch设为了YES;

因此,当触摸menu时,menu的优先级最高,所以第一个响应;然后将触摸Swallow掉,

当触摸屏幕非menu处,menu没有接收到触摸,SwallowTouchLayer接收到触摸,响应然后Swallow掉,所以HellowWorld不会响应触摸,看起来就是HelloWorld层的按钮全部失效。

(关于Swallow具体可以参照上一篇文章Cocos-2d CCLayer的触摸响应CCTouchDelegate和CCStandardTouchDelegate和 CCTargetedTouchDelegate)

7.在点击menu按钮,移除SwallowTouchLayer。

在onExit退出该层时,移除掉触摸代理

HelloWorldLayer又可继续交互,响应触摸。

8.说明:

这里只是一个小例子,演示了SwallowTouchLayer优先拦截touch响应。当然我们可以在SwallowTouchLayer中添加touchBegan、touchMove、touchEnd代理方法,实现SwallowTouchLayer特有的触摸方法。

转载于:https://blog.51cto.com/7212823/1202410

Cocos-2d 关于SwallowTouch,进一步解释触摸事件分发机制相关推荐

  1. 调用某个按钮事件_高级UI晋升之触摸事件分发机制(一)

    更多Android高级架构进阶视频学习请点击:https://space.bilibili.com/474380680 0. 前言 鉴于安卓分发机制较为复杂,故分为多个层次进行讲解,分别为基础篇.实践 ...

  2. 从源代码解释Android事件分发机制

    在ViewRootImpl的setView方法中.用户的触摸按键消息是体如今窗体上的.而windowManagerService则是管理这些窗体,它一旦接收到用户对窗体的一些触摸按键消息,会进行对应的 ...

  3. Android事件分发机制在实战开发中的应用之二

    学习的最终目标就是要学以致用,本文所分享的案例都是自己在公司实战开发过程中的真实案例,现在把它分享出来,希望对初学者有所帮助 版权声明:本文来自门心叼龙的博客,属于原创内容,转载请注明出处:https ...

  4. Android系统分析之带着问题看事件分发机制

    Android 触摸事件分发机制? Android系统分析之带着问题看事件分发机制 一 事件分发机制 1 什么是事件分发机制? 1.1 什么是事件? 答:当用户触摸屏幕时,每一次的点击,按下,移动,抬 ...

  5. Android6.0源码解读之ViewGroup点击事件分发机制

    本篇博文是Android点击事件分发机制系列博文的第三篇,主要是从解读ViewGroup类的源码入手,根据源码理清ViewGroup点击事件分发原理,明白ViewGroup和View点击事件分发的关系 ...

  6. 完全理解Android TouchEvent事件分发机制(一)

    本文能给你带来和解决一些你模糊的Touch事件概念及用法 1.掌握View及ViewGroup的TouchEvent事件分发机制 2.为解决View滑动冲突及点击事件消费提供支持 3.为你解决面试中的 ...

  7. android触摸事件分发,Android 事件分发机制

    Android 事件分发机制一直让人头痛,之前也是面向 GitHub 编程得过且过.今天下定决心了解一下,以便后面自己定制 View 效果.Android 触摸事件有三个基本类型:ACTION_DOW ...

  8. Android 的触摸反馈以及事件分发机制

    在Android系统中,当你点击App某个按钮从你按下到抬起到底发生了什么? 要想解释这个问题首先需要了解Android的几个事件类型. Android 的事件类型分为以下四种: 1.MotionEv ...

  9. Android之Android触摸事件传递机制

    转载请标明出处: http://blog.csdn.net/hai_qing_xu_kong/article/details/53431274 本文出自:[顾林海的博客] ##前言 关于Android ...

最新文章

  1. 02、在层级未知情况下通过递归查找子物体
  2. C# WPF MVVM模式下在主窗体显示子窗体并获取结果
  3. 2020前端最新面试题(vue篇)
  4. 谁给小鹏P5的勇气?
  5. 服务器link系统命令,可以使用命令(7)来查看网络接口的运行情况。输入该命令后,系统的输出信息如下。...
  6. 人人都能有数字替身:量子动力FACEGOOD发布AI交互实时数字人
  7. Python开源机器学习项目实战
  8. 联想电脑锁屏壁纸的缓存目录,历史壁纸+当前显示的锁屏壁纸,珍藏一下!
  9. Play 2.6 异步处理结果
  10. excel vba 数据分析
  11. ocr识别身份证护照阅读器
  12. 基于cesium的三维管线系统综述
  13. 微表面模型Beckmann–Spizzichino distribution的概率密度函数推导
  14. 计算机中丢失storm.d,win10 64位电脑缺少storm.dll怎么办_win10玩暗黑破坏神2缺少storm.dll文件修复方法...
  15. Word调查问卷表格统计
  16. 华为鸿蒙文案,机智的华为广告文案,各种“吊 打”三星小朋友!
  17. gsap_使用GSAP的动画库为Bootstrap传送带制作动画
  18. 北京小汽车出行比例首次下降
  19. 一张图认识URI和URL
  20. PSTN 与 PBX 业务

热门文章

  1. linux之ClamAV杀毒软件安装配置
  2. linux去掉空行的几种方法
  3. linux之mktemp命令
  4. 霍夫曼编码实验matlab,哈夫曼编码 MATLAB程序
  5. Hive Unable to instantiate org.apache.hadoop.hive.ql.metadata.SessionHiveMetaStoreClient
  6. 锋利的JQuery —— 事件和动画
  7. React从入门到精通系列之(14)refs和DOM元素
  8. PKCS #1 RSA Encryption Version 1.5
  9. 面试题 16.18. 模式匹配
  10. python装饰器函数执行后日志_python 某一函数上面有多个装饰器