我们时常需要这么些功能,弹出一个层,给与用户一些提示,这也是一种模态窗口,在没有对当前对话框进行确认的时候,不能继续往下操作。
我们设计一个对话框,对话框上有几个按钮(个数可定制),当然有个标题,会让别人一眼看出它之功用,里面可以有些详细的提示文字,需要是模态窗口,而且窗口的大小可变,这样能够更好的适应不同的屏幕的大小。当然还有一个重要的功能,弹出效果 ~ 虽然从技术角度来说,实现起来并不难,或者说非常简单,但这会以一个很好的用户体验展示给用户。
1.弹出框类
PopupLayer.h
// // PopupLayer.h // PopupDemo // // Created by IDEA-MAC03 on 13-10-10. // // #ifndef __PopupDemo__PopupLayer__ #define __PopupDemo__PopupLayer__ #include "cocos2d.h" #include "cocos-ext.h" using namespace cocos2d; using namespace cocos2d::extension; using namespace std; class PopupLayer:public CCLayer { public: PopupLayer(); ~PopupLayer(); virtual bool init(); CREATE_FUNC(PopupLayer); // 需要重写触摸注册函数,重新给定触摸级别 virtual void registerWithTouchDispatcher(void); // 重写触摸函数,永远返回 true ,屏蔽其它层,达到 “模态” 效果 bool ccTouchBegan(cocos2d::CCTouch *pTouch,cocos2d::CCEvent *pEvent); // 构架,并设置对话框背景图片 static PopupLayer* create(const char* backgroundImage); // 它可以显示标题,并且设定显示文字大小 void setTitle(const char*title,int fontsize = 20); // 文本内容,padding 为文字到对话框两边预留的距离,这是可控的,距上方的距离亦是如此 void setContentText(const char *text, int fontsize = 20, int padding = 50, int paddintTop = 100); // 回调函数,当点击按钮后,我们关闭弹出层的同事,需要一个回调函数,以通知我们点击了哪个按钮(如果有多个) void setCallbackFunc(CCObject* target, SEL_CallFuncN callfun); // 为了添加按钮方面,封装了一个函数,传入些必要的参数 bool addButton(const char* normalImage, const char* selectedImage, const char* title, int tag = 0); // 为了在显示层时之前的属性生效,选择在 onEnter 里动态展示 virtual void onEnter(); virtual void onExit(); private: void buttonCallback(CCObject* pSender); // 文字内容两边的空白区 int m_contentPadding; int m_contentPaddingTop; CCObject* m_callbackListener; SEL_CallFuncN m_callback; CC_SYNTHESIZE_RETAIN(CCMenu*, m__pMenu, MenuButton); CC_SYNTHESIZE_RETAIN(CCSprite*, m__sfBackGround, SpriteBackGround); CC_SYNTHESIZE_RETAIN(CCScale9Sprite*, m__s9BackGround, Sprite9BackGround); CC_SYNTHESIZE_RETAIN(CCLabelTTF*, m__ltTitle, LabelTitle); CC_SYNTHESIZE_RETAIN(CCLabelTTF*, m__ltContentText, LabelContentText); }; #endif /* defined(__PopupDemo__PopupLayer__) */
// // PopupLayer.cpp // PopupDemo // // Created by IDEA-MAC03 on 13-10-10. // // #include "PopupLayer.h" PopupLayer::PopupLayer(): m__pMenu(NULL) ,m_contentPadding(0) ,m_contentPaddingTop(0) ,m_callbackListener(NULL) ,m_callback(NULL) ,m__sfBackGround(NULL) ,m__s9BackGround(NULL) ,m__ltContentText(NULL) ,m__ltTitle(NULL) { } PopupLayer::~PopupLayer() { CC_SAFE_RELEASE(m__pMenu); CC_SAFE_RELEASE(m__sfBackGround); CC_SAFE_RELEASE(m__ltContentText); CC_SAFE_RELEASE(m__ltTitle); CC_SAFE_RELEASE(m__s9BackGround); } bool PopupLayer::init() { bool bRef = false; do { CC_BREAK_IF(!CCLayer::init()); this->setContentSize(CCSizeZero); // 初始化需要的 Menu CCMenu* menu = CCMenu::create(); menu->setPosition(CCPointZero); setMenuButton(menu); setTouchEnabled(true); bRef = true; } while (0); return bRef; } void PopupLayer::registerWithTouchDispatcher() { // 这里的触摸优先级设置为 -128 这保证了,屏蔽下方的触摸 CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, -128, true); } bool PopupLayer::ccTouchBegan(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent) { CCLog("PopupLayer touch"); return true; } PopupLayer* PopupLayer::create(const char *backgroundImage) { PopupLayer* ml = PopupLayer::create(); ml->setSpriteBackGround(CCSprite::create(backgroundImage)); ml->setSprite9BackGround(CCScale9Sprite::create(backgroundImage)); return ml; } void PopupLayer::setTitle(const char*title,int fontsize) { CCLabelTTF* ltfTitle = CCLabelTTF::create(title, "", fontsize); setLabelTitle(ltfTitle); } void PopupLayer::setContentText(const char *text, int fontsize, int padding, int paddingTop){ CCLabelTTF* ltf = CCLabelTTF::create(text, "", fontsize); setLabelContentText(ltf); m_contentPadding = padding; m_contentPaddingTop = paddingTop; } void PopupLayer::setCallbackFunc(cocos2d::CCObject *target, SEL_CallFuncN callfun) { m_callbackListener = target; m_callback = callfun; } bool PopupLayer::addButton(const char *normalImage, const char *selectedImage, const char *title, int tag){ CCSize winSize = CCDirector::sharedDirector()->getWinSize(); CCPoint pCenter = ccp(winSize.width / 2, winSize.height / 2); // 创建图片菜单按钮 CCMenuItemImage* menuImage = CCMenuItemImage::create(normalImage, selectedImage, this, menu_selector(PopupLayer::buttonCallback)); menuImage->setTag(tag); menuImage->setPosition(pCenter); // 添加文字说明并设置位置 CCSize imenu = menuImage->getContentSize(); CCLabelTTF* ttf = CCLabelTTF::create(title, "", 20); ttf->setColor(ccc3(0, 0, 0)); ttf->setPosition(ccp(imenu.width / 2, imenu.height / 2)); menuImage->addChild(ttf); getMenuButton()->addChild(menuImage); return true; } void PopupLayer::buttonCallback(cocos2d::CCObject *pSender){ CCNode* node = dynamic_cast<CCNode*>(pSender); CCLog("touch tag: %d", node->getTag()); if (m_callback && m_callbackListener){ (m_callbackListener->*m_callback)(node); } this->removeFromParentAndCleanup(true); } void PopupLayer::onEnter() { CCLayer::onEnter(); CCSize winSize = CCDirector::sharedDirector()->getWinSize(); CCPoint pCenter = ccp(winSize.width / 2, winSize.height / 2); CCSize contentSize; // 设定好参数,在运行时加载 if (getContentSize().equals(CCSizeZero)) { getSpriteBackGround()->setPosition(ccp(winSize.width / 2, winSize.height / 2)); this->addChild(getSpriteBackGround(),0,0); contentSize = getSpriteBackGround()->getTexture()->getContentSize(); }else { CCScale9Sprite *background = getSprite9BackGround(); background->setContentSize(getContentSize()); background->setPosition(ccp(winSize.width / 2, winSize.height / 2)); this->addChild(background,0); contentSize = getContentSize(); } // 添加按钮,并设置其位置 this->addChild(getMenuButton()); float btnWidth = contentSize.width/(getMenuButton()->getChildrenCount()+1); CCArray* array = getMenuButton()->getChildren(); CCObject* pObj = NULL; int i = 0; CCARRAY_FOREACH(array, pObj) { CCNode* node = dynamic_cast<CCNode*>(pObj); node->setPosition(ccp(winSize.width / 2 - contentSize.width / 2 + btnWidth * (i + 1), winSize.height / 2 - contentSize.height / 3)); i++; } // 显示对话框标题 if (getLabelTitle()) { getLabelTitle()->setPosition(ccpAdd(pCenter, ccp(0, contentSize.height / 2 - 35.0f))); this->addChild(getLabelTitle()); } // 显示文本内容 if (getLabelContentText()) { CCLabelTTF* ltf = getLabelContentText(); ltf->setPosition(ccp(winSize.width / 2, winSize.height / 2)); ltf->setDimensions(CCSizeMake(contentSize.width - m_contentPadding * 2, contentSize.height - m_contentPaddingTop)); ltf->setHorizontalAlignment(kCCTextAlignmentLeft); this->addChild(ltf); } CCAction* popupLayer = CCSequence::create(CCScaleTo::create(0.0, 0.0), CCScaleTo::create(0.06, 1.05), CCScaleTo::create(0.08, 0.95), CCScaleTo::create(0.08, 1.0), NULL); this->runAction(popupLayer); } void PopupLayer::onExit() { CCLog("popup on exit."); CCLayer::onExit(); }
HelloWorldScene.h
#ifndef __HELLOWORLD_SCENE_H__ #define __HELLOWORLD_SCENE_H__ #include "cocos2d.h" class HelloWorld : public cocos2d::CCLayer { public: // Method 'init' in cocos2d-x returns bool, instead of 'id' in cocos2d-iphone (an object pointer) virtual bool init(); // there's no 'id' in cpp, so we recommend to return the class instance pointer static cocos2d::CCScene* scene(); // a selector callback void menuCloseCallback(CCObject* pSender); // preprocessor macro for "static create()" constructor ( node() deprecated ) CREATE_FUNC(HelloWorld); void menuCallback(cocos2d::CCObject *pSender); void popupLayer(); void buttonCallback(cocos2d::CCNode *pNode); }; #endif // __HELLOWORLD_SCENE_H__
#include "HelloWorldScene.h" #include "SimpleAudioEngine.h" #include "PopupLayer.h" using namespace cocos2d; using namespace CocosDenshion; CCScene* HelloWorld::scene() { // 'scene' is an autorelease object CCScene *scene = CCScene::create(); // 'layer' is an autorelease object HelloWorld *layer = HelloWorld::create(); // add layer as a child to scene scene->addChild(layer); // return the scene return scene; } // on "init" you need to initialize your instance bool HelloWorld::init() { ////////////////////////////// // 1. super init first if ( !CCLayer::init() ) { return false; } CCSize winSize = CCDirector::sharedDirector()->getWinSize(); CCPoint pointCenter = ccp(winSize.width / 2, winSize.height / 2); // 添加背景图片 CCSprite* background = CCSprite::create("HelloWorld.png"); background->setPosition(pointCenter); background->setScale(1.5f); this->addChild(background); // 添加菜单 CCMenu* menu = CCMenu::create(); CCMenuItemFont* menuItem = CCMenuItemFont::create("popup", this, menu_selector(HelloWorld::menuCallback)); menuItem->setPosition(ccp(winSize.width / 2, winSize.height / 2)); menuItem->setColor(ccc3(0, 0, 0)); menu->addChild(menuItem); menu->setPosition(CCPointZero); this->addChild(menu); return true; } void HelloWorld::menuCallback(cocos2d::CCObject *pSender){ popupLayer(); } void HelloWorld::popupLayer() { // 定义一个弹出层,传入一张背景图 PopupLayer* pl = PopupLayer::create("useDialogBox0u00001.png"); // ContentSize 是可选的设置,可以不设置,如果设置把它当作 9 图缩放 pl->setContentSize(CCSizeMake(400, 360)); pl->setTitle("吾名一叶"); pl->setContentText("娇兰傲梅世人赏,却少幽芬暗里藏。不看百花共争艳,独爱疏樱一枝香。", 20, 50, 150); // 设置回调函数,回调传回一个 CCNode 以获取 tag 判断点击的按钮 // 这只是作为一种封装实现,如果使用 delegate 那就能够更灵活的控制参数了 pl->setCallbackFunc(this, callfuncN_selector(HelloWorld::buttonCallback)); // 添加按钮,设置图片,文字,tag 信息 pl->addButton("shopBtn0s01.png", "shopBtn0s02.png", "确定", 0); pl->addButton("bagButton0b1.png", "bagButton0b2.png", "取消", 1); // 添加到当前层 this->addChild(pl); } void HelloWorld::buttonCallback(cocos2d::CCNode *pNode){ CCLog("button call back. tag: %d", pNode->getTag()); } void HelloWorld::menuCloseCallback(CCObject* pSender) { CCDirector::sharedDirector()->end(); #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) exit(0); #endif }
如上,完成了对话框的基本模型,它实现了以下功能:
当然还有许多其它并没有照顾到的功能,或者不完善的地方,这就需要用户自己扩展,定制了,如,这样一个层,至少应该是单例的,任何时候只应该存在一个,可以用单例模式实现,对于弹出层的内容方面,这里只有标题和内容,并且标题位置固定,按钮的位置还可以更灵活的设置等。
详解文章:http://www.ityran.com/archives/4854