委托方式完成 场景类中实现模态框(弹出框)中的点击事件

本文介绍了如何在GameScene类中处理模态层(PopupLayer)中的点击事件,而非在模态层自身。通过创建委托类PopupNumberDelegate,将点击事件的处理逻辑移到GameScene。当模态层中的精灵被点击并松开时,调用delegate的spriteOnTouchEnded方法。GameScene继承PopupNumberDelegate并实现该方法,实现了事件处理的委托机制。
摘要由CSDN通过智能技术生成

这个需求是这样的

有一个场景类GameScene。这个类要addchild一个模态层(弹出层)的layer。模态层中有一个或几个按钮。


我现在不想(或是不能)把模态层中某一个sprite的点击事件写到模态层这个类中,而是要写到GameScene类中。如何实现呢?


看到网上一篇PopupLayer实现的例子。里面有一个方法,其中最重要的一句话是这个

void PopupLayer::buttonCallBack(Ref* pSender){
	Node* node = dynamic_cast<Node*>(pSender);
	CCLog("【====PopupLayer::buttonCallBack====】touch tag: %d", node->getTag());
	if (m_callback && m_callbackListener){
		(m_callbackListener->*m_callback)(node);
	}
	this->removeFromParent();
}

说心里话。对C++现在还不是很熟。这个
(m_callbackListener->*m_callback)(node);
我研究了半天也没弄明白是个什么原理。当然按照他的例子写是可以正常运行的。不过我希望我的每一行代码都可以知其然并且知其所以然。于是我毅然决然的换了另外一种实现方式。即委托。


其实C++本身是不像OC那样有委托的。不过好在我们可以很方便的委婉的实现这一机制。


首先新建一个委托类PopupNumberDelegate.h

#ifndef __POPUP_NUMBER_DELEGATE_H__
#define __POPUP_NUMBER_DELEGATE_H__

//popupnumber模态框委托
class PopupNumberDelegate
{
public:
	virtual void spriteOnTouchEnded() = 0;
};

#endif // __POPUP_NUMBER_DELEGATE_H__

这个委托类里面只有一个纯虚方法。即spriteOnTouchEnded。我们GameScene类中最后要实现这个委托方法。

整个逻辑就是,模态层中的sprite点击后,会触发spriteOnTouchEnded这个委托方法。然后我们在GameScene中实现这个委托方法即可。


接下来是模态层

PopupNumberLayer.h

#ifndef __POPUP_NUMBER_LAYER_H__
#define __POPUP_NUMBER_LAYER_H__

#include "cocos2d.h"
#include "extensions/cocos-ext.h"
#include "PopupNumberDelegate.h"

USING_NS_CC;
USING_NS_CC_EXT;

class PopupNumberLayer : public LayerColor{
public:
	virtual bool init();
	CREATE_FUNC(PopupNumberLayer);
	static PopupNumberLayer* createLayer();

	PopupNumberDelegate* _delegate;
private:
	Size visibleSize;
	Vec2 origin;

	//touch事件监听 屏蔽向下触摸
	bool onTouchBegan(Touch *touch, Event *event);
	void onTouchMoved(Touch *touch, Event *event);
	void onTouchEnded(Touch* touch, Event* event);
	bool onSpriteTouchBegan(Touch* touch, Event* event);
	void onSpriteTouchEnded(Touch* touch, Event* event);
};

#endif // __POPUP_NUMBER_LAYER_H__

PopupNumberLayer.cpp

#include "PopupNumberLayer.h"

bool PopupNumberLayer::init(){
	if (!LayerColor::init()){
		return false;
	}

	visibleSize = Director::getInstance()->getVisibleSize();
	origin = Director::getInstance()->getVisibleOrigin();

	setColor(ccc3(0, 0, 0));
	setOpacity(128);

	//add layer touch event
	auto mylistener = EventListenerTouchOneByOne::create();
	mylistener->setSwallowTouches(true);
	mylistener->onTouchBegan = CC_CALLBACK_2(PopupNumberLayer::onTouchBegan, this);
	mylistener->onTouchMoved = CC_CALLBACK_2(PopupNumberLayer::onTouchMoved, this);
	mylistener->onTouchEnded = CC_CALLBACK_2(PopupNumberLayer::onTouchEnded, this);
	Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(mylistener, this);

	auto sprite = Sprite::createWithSpriteFrameName("block_3.png");
	sprite->setPosition(Vec2(visibleSize / 2));
	this->addChild(sprite);

	auto listener = EventListenerTouchOneByOne::create();
	listener->setSwallowTouches(true);
	listener->onTouchBegan = CC_CALLBACK_2(PopupNumberLayer::onSpriteTouchBegan, this);
	listener->onTouchEnded = CC_CALLBACK_2(PopupNumberLayer::onSpriteTouchEnded, this);
	Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener, sprite);

	return true;
}

PopupNumberLayer* PopupNumberLayer::createLayer()
{
	auto layerColor = PopupNumberLayer::create();

	return layerColor;
}

bool PopupNumberLayer::onSpriteTouchBegan(Touch* touch, Event* event)
{
	// 获取事件所绑定的 target 
	auto target = static_cast<Sprite*>(event->getCurrentTarget());

	// 获取当前点击点所在相对按钮的位置坐标
	Point locationInNode = target->convertToNodeSpace(touch->getLocation());
	Size s = target->getContentSize();
	Rect rect = Rect(0, 0, s.width, s.height);

	// 点击范围判断检测
	if (rect.containsPoint(locationInNode))
	{
		log("sprite 坐标 ... x = %f, y = %f", locationInNode.x, locationInNode.y);
		target->setOpacity(180);
		return true;
	}
	return false;
}

void PopupNumberLayer::onSpriteTouchEnded(Touch* touch, Event* event)
{
	this->_delegate->spriteOnTouchEnded();
}

bool PopupNumberLayer::onTouchBegan(Touch *touch, Event *event){
	return true;
}

void PopupNumberLayer::onTouchMoved(Touch *touch, Event *event){

}

void PopupNumberLayer::onTouchEnded(Touch* touch, Event* event){

}

所有代码都很简单。这里最重要的就是一个地方。

点击sprite并且松开时候,会触发onSpriteTouchEnded方法。在onSpriteTouchEnded方法中又这么一句话this->_delegate->spriteOnTouchEnded();


同时在.h的声明中声明了这个变量PopupNumberDelegate* _delegate;


这里就是重点。即我们点击sprite并且松开后,会执行PopupNumberDelegate类中的spriteOnTouchEnded()方法。


那么spriteOnTouchEnded方法我们写的是一个纯虚方法。接下来怎么办呢?很简单。GameScene继承PopupNumberDelegate类,并且实现这个虚方法,就达到了我们的目的。接下来看代码,我只保留我们最需要关注的一部分代码

GameScene.h

#ifndef __GAME_SCENE_H__
#define __GAME_SCENE_H__
#include "cocos2d.h"

#include "PopupNumberLayer.h"
#include "PopupNumberDelegate.h"

USING_NS_CC;

class GameScene : public cocos2d::Layer, public PopupNumberDelegate
{
public:
	static Scene* createScene();
	virtual bool init();
	virtual void spriteOnTouchEnded();
	CREATE_FUNC(GameScene);
private:
	Size visibleSize;
	Vec2 origin;
	PopupNumberLayer* _popupNumberLayer;
};

#endif // __GAME_SCENE_H__

GameScene.cpp

#include "GameScene.h"


Scene* GameScene::createScene()
{
	auto scene = Scene::create();
	auto layer = GameScene::create();

	scene->addChild(layer);

	return scene;
}

bool GameScene::init()
{
	if (!Layer::init())
	{
		return false;
	}

	visibleSize = Director::getInstance()->getVisibleSize();
	origin = Director::getInstance()->getVisibleOrigin();

	//添加模态框
	_popupNumberLayer = PopupNumberLayer::createLayer();
	_popupNumberLayer->_delegate = this;
	this->addChild(_popupNumberLayer);
	
	return true;
}

void GameScene::spriteOnTouchEnded()
{
	CCLOG("点击了sprite");
}

这时候运行项目。会出现一个模态框。点击模态框中的sprite后,会依次显示“sprite 坐标 ... x = xxx, y = xxx”,"点击了sprite"。


完美解决

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值