弹出框及层的屏蔽功能实现

来源:互联网 发布:企业网站中英文版源码 编辑:程序博客网 时间:2024/06/05 03:01

一般游戏都会用到弹出框(退出提示,设置,战斗胜利等),初学者都会遇到这类的问题。要做一个弹出框的效果可能相对比较简单,但在实际开发中常常会遇到一些麻烦,就是点击弹出框的部分背后的事件也会响应,仅仅是这样的效果达不到要求。


小编初学这个的时候也会遇到这类问题,常常的解决方式就是度娘。


网上的方式大都很繁琐,不易理解,还有就是版本年代久远现在不适用,(小编的版本是cocos2dx 3.10)。


比如网上流行的一种方式是创建场景,即在原场景中在创建一个场景实现弹框效果,然后改变触摸优先级的大小,优先对最外层的场景触摸。这种方法理论上会实现,但是小编作为一个初学者这种方式理解相对较难。另外创建场景的方式会多创两个文件(头文件,cpp文件),如果仅仅只是显示几个文字,这样的方式显得很累赘,无疑增加代码量。(个人见解,无意冒犯)。


我今天讲的就是用创建的层的方式创建一个弹出框,然后用层截断的方式屏蔽背后的触摸。


这里做了一个测试在原层上创建了一个精灵 ,可以点击拖动。一个(点击弹出层)的按钮,点击就会弹出第三图的灰色的层。

没有弹出层的时候可以拖动精灵的位置,弹出层出现后,屏蔽了背后的响应事件,就不能拖动了。


也许大家有疑问这与弹框有什么联系,这个弹出层的大小可以设置,可以设置成想要的大小。层上面可以添加东西,与原层的添加方式一样,这里我在弹出层上添加了一个按钮(右下角),点击可以关闭弹出层。这里设置弹出层的目的是屏蔽背后的事件响应,所有我这里的弹出层的大小与显示区域大小一样。

#include "TestCeng.h"Scene* TestCeng::createScene(){auto scene = Scene::create();auto layer = TestCeng::create();scene->addChild(layer);return scene;}bool TestCeng::init(){if (!Layer::init()){return false;}Size visibleSize = Director::getInstance()->getVisibleSize();Vec2 origin = Director::getInstance()->getVisibleOrigin();//顶部显示标签Dictionary* strings = Dictionary::createWithContentsOfFile("string.xml");const char * str;//获取string.xml文件键值str = ((String *)strings->objectForKey("cenglogo"))->getCString();auto label = Label::createWithSystemFont(str, "", 30);label->setPosition(Vec2(visibleSize.width / 2, visibleSize.height*0.85));this->addChild(label, 2);//创建可以移动的精灵auto spr = Sprite::create("HelloWorld.png");spr->setTag(1);spr->setScale(0.5);spr->setPosition(Point(visibleSize.width / 2, visibleSize.height / 2));this->addChild(spr);//创建底部按钮str = ((String *)strings->objectForKey("ceng"))->getCString();auto button = MenuItemFont::create(str, CC_CALLBACK_0(TestCeng::createLayer, this));auto menu = Menu::create(button, NULL);menu->setPosition(Point(visibleSize.width / 2, visibleSize.height*0.2));this->addChild(menu, 2);//添加触摸事件auto listener = EventListenerTouchOneByOne::create();listener->setSwallowTouches(true);listener->onTouchBegan = CC_CALLBACK_2(TestCeng::onTouchBegan, this);listener->onTouchMoved = CC_CALLBACK_2(TestCeng::onTouchMoved, this);Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener, spr);return true;}void TestCeng::createLayer(){Size visibleSize = Director::getInstance()->getVisibleSize();//创建一个弹出层auto layer = LayerColor::create(Color4B(100, 180, 180, 180));layer->setContentSize(visibleSize);//设置与可显示区域大小一样layer->setPosition(Vec2::ZERO);this->addChild(layer,3);//层上添加一个返回按钮auto button = MenuItemImage::create("fanhui.jpg", "fanhui.jpg", CC_CALLBACK_0(TestCeng::menuCloseCallback, this));button->setScale(0.2);auto menu = Menu::create(button, NULL);menu->setPosition(Point(layer->getContentSize().width*0.95, layer->getContentSize().height*0.05));layer->addChild(menu);//对该层添加触摸事件 用于屏蔽背后的触摸事件auto listener = EventListenerTouchOneByOne::create();listener->setSwallowTouches(true);//实现屏蔽listener->onTouchBegan = [=](Touch *touch, Event *event) {Point location = touch->getLocation();if(layer->getBoundingBox().containsPoint(location))return true;};//绑定layer的触摸事件Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener, layer);}bool TestCeng::onTouchBegan(Touch *touch, Event *event){Point location = touch->getLocation();auto spr = (Sprite*)this->getChildByTag(1);if (spr->getBoundingBox().containsPoint(location))return true;return false;}void TestCeng::onTouchMoved(Touch *touch, Event *event){auto spr = (Sprite*)this->getChildByTag(1);spr->setPosition(spr->getPosition() + touch->getDelta());}void TestCeng::menuCloseCallback(){this->removeChild(this->getChildByTag(2));}

init方法里创建一个顶部标签,精灵,按钮,对精灵绑定监听事件,
点击按钮进入createLayer方法,创建一个与显示区域大小一样的层,层上添加了一个返回按钮,点击移除该层。

重点说的是listener监听事件 setSwallowTouches设置触摸不可穿透,用addEventListenerWithSceneGraphPriority方式绑定监听,分别对精灵和层绑定。不建议用优先级的方式绑定。把弹出层的Z轴设在最上面,然后它将显示在最外层,触摸事件发生在层上时,return true就返回了。

在弹出层的触摸事件Began里获取弹出层的大小并判断触摸点是否在层上,在层上就截断触摸,没有自然就不会响应。这样大家就可以任意设置弹出层的大小,实现某一区域的触摸截断了。


原创粉丝点击