本站文章转载务必在明显处注明:原文链接: http://blog.csdn.net/cjsen/article/details/9055389
此博客基于Cocos2d-2.1rc0-x-2.1.3 API
参考博客:http://blog.csdn.net/onerain88/article/details/7608496
前言
在cocos2d-x中为我们提示提供CCMessageBox,这个并不是完全跨平台,而是分平台实现而且是调用系统级的的对话框,只能说界面好丑.我们可以利用CCLayerColor自定义一个模态的对话框。
实现的功能
1)用户的点击事件只能在模态对话框上响应,而底下的层无法响应事件
2)如系统的对话框一样,当点击框的按键时能消失;
针对上面的第二个问题很简单,只要点击事件调用
layer->removeFromParentAndCleanup(true);
下面针对第一个问题说明一下:
在Cocos2d上事件的响应并不会按照addChild(object)的添加顺序去响应会个精灵或层的事件的,而是按照优先级priority的大小去分发事件,另外priority值越小优先级越高,在cocos2d默认下 CCMenu的优先级的最高的kCCMenuHandlerPriority = -128,所以我们要做的是,在我们自定义的层注册会优先级比菜单高(即kCCMenuHandlerPriority-1),这样就不会响应对话框底部的CCMenu,但有个问题,这样会连我们在对话框上的菜单(或其他需要响应事件的CCNode)都无法响应事件,这个是要靠我们自己把获取的事件分发给在对话框中需要响应事件的元素;
实现
首先我们先继承自CCLayerColor类UIDialogLayer(在CCLayerColor上我们可以设置半透时效果,更像系统模态窗口),我们先针对几个关键的地方说明一下,最后再加源码链接,先上最后的效果图
PS:按照ios上的UIAlertView模仿了一下(其他更好看的效果就靠大家了^_^),基本的功能就在源码上
第一步:在CCLayerColor生成时注册事件获取,并在退出时注销
void UIDialogLayer::onEnter(){
CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, kCCMenuHandlerPriority-1 , true);
CCNode::onEnter();
};
void UIDialogLayer::onExit(){
CCDirector::sharedDirector()->getTouchDispatcher()->removeDelegate(this);
CCNode::onExit();
};
上面的代码可替换为,在初始化时设置几个CCLayerColor的属性
dialogLayer->setTouchPriority(kCCMenuHandlerPriority-1);//设置优先级
dialogLayer->setTouchMode(kCCTouchesOneByOne);//设置触摸模式
dialogLayer->setTouchEnabled(true);//是否可触摸
两种的效果是一样的
第二步:重写点击响应事件,并分发事件
1)这里是初始化两个CCControlButton,做为对话框的按钮(上面的参考博客是用菜单CCMenu)
CCControlButton *m_pButton;//记录在响应的按钮
bool m_bTouchedControl;// 记录是否已点击到对话框的精灵
CCArray *m_buttonArray;//保存所有要响应事件的容器(这里是保存CCControlButton)
在之后的初始化按钮后,都会添加到m_buttonArray上,在之后的ccTouchBegan事件上会遍历出点击到哪个按钮并记录下来,进行事件分发
bool UIDialogLayer::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent){
CCObject *object = NULL;
CCARRAY_FOREACH(m_buttonArray, object){
CCControlButton* controlButton = (CCControlButton*)object;
m_bTouchedControl = controlButton->ccTouchBegan(pTouch, pEvent);
if (m_bTouchedControl == true) {
m_pButton = controlButton;
break;
}
}
return true;
};
在其他的事件回调函数中都要写,如下
void UIDialogLayer::ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent){
if (m_bTouchedControl == true) {
m_pButton->ccTouchMoved(pTouch, pEvent);
}
};
void UIDialogLayer::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent){
if (m_bTouchedControl == true) {
m_pButton->ccTouchEnded(pTouch, pEvent);
}
};
void UIDialogLayer::ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent){
if (m_bTouchedControl == true) {
m_pButton->ccTouchCancelled(pTouch, pEvent);
}
};
上面的两步已经完成了基本工作,只要在CCControlButton事件响应中调用 this ->removeFromParentAndCleanup ( true );即可;
为了跟IOS上的UIAlertView更接近,如点击某个按钮可以知道,是哪个按钮,所以我们这里自定义了UIDialogLayerDelegate
第三步:完成UIDialogLayerDelegate,按钮事件回调
class UIDialogLayer;
class UIDialogLayerDelegate{
public:
virtual ~UIDialogLayerDelegate(){};
/**
* @brief 点击按钮时触发
*
* @param dialogLayer 回调对象
* @param buttonIndex 按钮索引
*/
virtual void uidialogLayerClickedButtonAtIndex(UIDialogLayer *dialogLayer, int buttonIndex){};
};
在UIDialogLayer初始化时传入委托对象,在点击事件上回调Delegate即可
static UIDialogLayer* initDialog(UIDialogLayerDelegate* delegate,const char* title, const char* message, const char* canceButTitle, const char* otherButTitle);
//点击按钮时触发
void UIDialogLayer::dialogAction(CCControlButton* controlButton){
m_delegate->uidialogLayerClickedButtonAtIndex(this, controlButton->getTag());
this->removeFromParentAndCleanup(true);
};
上面的tag是按照CCControlButton添加的顺序,从0开始加,这样方便对应按钮的索引;
最后,外部使用
UIDialogLayer *dialogLayer = UIDialogLayer::initDialog(this, "提示", "这就提示框", "取消", "确定");
this->addChild(dialogLayer);
在使用的类上,继承UIDialogLayerDelegate类 并实现方法
void HelloWorld::uidialogLayerClickedButtonAtIndex(UIDialogLayer *dialogLayer, int buttonIndex){
CCLog("buttonIndex = %d",buttonIndex);
}
这此就结束了哦