Cocos2d-x 弹出对话框的设计与实现
我们时常需要这么些功能,弹出一个层,给与用户一些提示,这也是一种模态窗口,在没有对当前对话框进行确认的时候,不能继续往下操作。
功能分析
我们设计一个对话框,对话框上有几个按钮(个数可定制),当然有个标题,会让别人一眼看出它之功用,里面可以有些详细的提示文字,需要是模态窗口,而且窗口的大小可变,这样能够更好的适应不同的屏幕的大小。当然还有一个重要的功能,弹出效果 ~ 虽然从技术角度来说,实现起来并不难,或者说非常简单,但这会以一个很好的用户体验展示给用户。
代码
1.弹出框类
PopupLayer.h
1 //
2 // PopupLayer.h
3 // PopupDemo
4 //
5 // Created by IDEA-MAC03 on 13-10-10.
6 //
7 //
8
9 #ifndef __PopupDemo__PopupLayer__
10 #define __PopupDemo__PopupLayer__
11
12 #include "cocos2d.h"
13 #include "cocos-ext.h"
14 using namespace cocos2d;
15 using namespace cocos2d::extension;
16 using namespace std;
17
18
19
20 class PopupLayer:public CCLayer
21 {
22
23 public:
24 PopupLayer();
25 ~PopupLayer();
26
27 virtual bool init();
28 CREATE_FUNC(PopupLayer);
29
30 // 需要重写触摸注册函数,重新给定触摸级别
31 virtual void registerWithTouchDispatcher(void);
32 // 重写触摸函数,永远返回 true ,屏蔽其它层,达到 “模态” 效果
33 bool ccTouchBegan(cocos2d::CCTouch *pTouch,cocos2d::CCEvent *pEvent);
34 // 构架,并设置对话框背景图片
35 static PopupLayer* create(const char* backgroundImage);
36
37 // 它可以显示标题,并且设定显示文字大小
38 void setTitle(const char*title,int fontsize = 20);
39 // 文本内容,padding 为文字到对话框两边预留的距离,这是可控的,距上方的距离亦是如此
40 void setContentText(const char *text, int fontsize = 20, int padding = 50, int paddintTop = 100);
41 // 回调函数,当点击按钮后,我们关闭弹出层的同事,需要一个回调函数,以通知我们点击了哪个按钮(如果有多个)
42 void setCallbackFunc(CCObject* target, SEL_CallFuncN callfun);
43 // 为了添加按钮方面,封装了一个函数,传入些必要的参数
44 bool addButton(const char* normalImage, const char* selectedImage, const char* title, int tag = 0);
45
46 // 为了在显示层时之前的属性生效,选择在 onEnter 里动态展示
47 virtual void onEnter();
48 virtual void onExit();
49
50 private:
51
52 void buttonCallback(CCObject* pSender);
53
54 // 文字内容两边的空白区
55 int m_contentPadding;
56 int m_contentPaddingTop;
57
58 CCObject* m_callbackListener;
59 SEL_CallFuncN m_callback;
60
61 CC_SYNTHESIZE_RETAIN(CCMenu*, m__pMenu, MenuButton);
62 CC_SYNTHESIZE_RETAIN(CCSprite*, m__sfBackGround, SpriteBackGround);
63 CC_SYNTHESIZE_RETAIN(CCScale9Sprite*, m__s9BackGround, Sprite9BackGround);
64 CC_SYNTHESIZE_RETAIN(CCLabelTTF*, m__ltTitle, LabelTitle);
65 CC_SYNTHESIZE_RETAIN(CCLabelTTF*, m__ltContentText, LabelContentText);
66
67 };
68
69
70
71
72 #endif /* defined(__PopupDemo__PopupLayer__) */
PopupLayer.cpp
1 //
2 // PopupLayer.cpp
3 // PopupDemo
4 //
5 // Created by IDEA-MAC03 on 13-10-10.
6 //
7 //
8
9 #include "PopupLayer.h"
10
11
12
13 PopupLayer::PopupLayer():
14 m__pMenu(NULL)
15 ,m_contentPadding(0)
16 ,m_contentPaddingTop(0)
17 ,m_callbackListener(NULL)
18 ,m_callback(NULL)
19 ,m__sfBackGround(NULL)
20 ,m__s9BackGround(NULL)
21 ,m__ltContentText(NULL)
22 ,m__ltTitle(NULL)
23 {
24
25 }
26
27 PopupLayer::~PopupLayer()
28 {
29 CC_SAFE_RELEASE(m__pMenu);
30 CC_SAFE_RELEASE(m__sfBackGround);
31 CC_SAFE_RELEASE(m__ltContentText);
32 CC_SAFE_RELEASE(m__ltTitle);
33 CC_SAFE_RELEASE(m__s9BackGround);
34 }
35
36 bool PopupLayer::init()
37 {
38 bool bRef = false;
39 do
40 {
41 CC_BREAK_IF(!CCLayer::init());
42 this->setContentSize(CCSizeZero);
43 // 初始化需要的 Menu
44 CCMenu* menu = CCMenu::create();
45 menu->setPosition(CCPointZero);
46 setMenuButton(menu);
47 setTouchEnabled(true);
48 bRef = true;
49 } while (0);
50 return bRef;
51 }
52
53
54 void PopupLayer::registerWithTouchDispatcher()
55 {
56 // 这里的触摸优先级设置为 -128 这保证了,屏蔽下方的触摸
57 CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, -128, true);
58 }
59
60 bool PopupLayer::ccTouchBegan(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent)
61 {
62 CCLog("PopupLayer touch");
63 return true;
64 }
65
66
67 PopupLayer* PopupLayer::create(const char *backgroundImage)
68 {
69 PopupLayer* ml = PopupLayer::create();
70 ml->setSpriteBackGround(CCSprite::create(backgroundImage));
71 ml->setSprite9BackGround(CCScale9Sprite::create(backgroundImage));
72 return ml;
73 }
74
75
76 void PopupLayer::setTitle(const char*title,int fontsize)
77 {
78 CCLabelTTF* ltfTitle = CCLabelTTF::create(title, "", fontsize);
79 setLabelTitle(ltfTitle);
80 }
81
82 void PopupLayer::setContentText(const char *text, int fontsize, int padding, int paddingTop){
83 CCLabelTTF* ltf = CCLabelTTF::create(text, "", fontsize);
84 setLabelContentText(ltf);
85 m_contentPadding = padding;
86 m_contentPaddingTop = paddingTop;
87 }
88
89 void PopupLayer::setCallbackFunc(cocos2d::CCObject *target, SEL_CallFuncN callfun)
90 {
91 m_callbackListener = target;
92 m_callback = callfun;
93 }
94
95
96 bool PopupLayer::addButton(const char *normalImage, const char *selectedImage, const char *title, int tag){
97 CCSize winSize = CCDirector::sharedDirector()->getWinSize();
98 CCPoint pCenter = ccp(winSize.width / 2, winSize.height / 2);
99
100 // 创建图片菜单按钮
101 CCMenuItemImage* menuImage = CCMenuItemImage::create(normalImage, selectedImage, this, menu_selector(PopupLayer::buttonCallback));
102 menuImage->setTag(tag);
103 menuImage->setPosition(pCenter);
104
105 // 添加文字说明并设置位置
106 CCSize imenu = menuImage->getContentSize();
107 CCLabelTTF* ttf = CCLabelTTF::create(title, "", 20);
108 ttf->setColor(ccc3(0, 0, 0));
109 ttf->setPosition(ccp(imenu.width / 2, imenu.height / 2));
110 menuImage->addChild(ttf);
111
112 getMenuButton()->addChild(menuImage);
113 return true;
114 }
115
116
117 void PopupLayer::buttonCallback(cocos2d::CCObject *pSender){
118 CCNode* node = dynamic_cast<CCNode*>(pSender);
119 CCLog("touch tag: %d", node->getTag());
120 if (m_callback && m_callbackListener){
121 (m_callbackListener->*m_callback)(node);
122 }
123 this->removeFromParentAndCleanup(true);
124 }
125
126
127
128 void PopupLayer::onEnter()
129 {
130 CCLayer::onEnter();
131
132 CCSize winSize = CCDirector::sharedDirector()->getWinSize();
133 CCPoint pCenter = ccp(winSize.width / 2, winSize.height / 2);
134
135 CCSize contentSize;
136 // 设定好参数,在运行时加载
137 if (getContentSize().equals(CCSizeZero))
138 {
139 getSpriteBackGround()->setPosition(ccp(winSize.width / 2, winSize.height / 2));
140 this->addChild(getSpriteBackGround(),0,0);
141 contentSize = getSpriteBackGround()->getTexture()->getContentSize();
142 }else
143 {
144 CCScale9Sprite *background = getSprite9BackGround();
145 background->setContentSize(getContentSize());
146 background->setPosition(ccp(winSize.width / 2, winSize.height / 2));
147 this->addChild(background,0);
148 contentSize = getContentSize();
149 }
150
151
152 // 添加按钮,并设置其位置
153 this->addChild(getMenuButton());
154 float btnWidth = contentSize.width/(getMenuButton()->getChildrenCount()+1);
155
156 CCArray* array = getMenuButton()->getChildren();
157 CCObject* pObj = NULL;
158 int i = 0;
159 CCARRAY_FOREACH(array, pObj)
160 {
161 CCNode* node = dynamic_cast<CCNode*>(pObj);
162 node->setPosition(ccp(winSize.width / 2 - contentSize.width / 2 + btnWidth * (i + 1), winSize.height / 2 - contentSize.height / 3));
163 i++;
164 }
165
166 // 显示对话框标题
167 if (getLabelTitle())
168 {
169 getLabelTitle()->setPosition(ccpAdd(pCenter, ccp(0, contentSize.height / 2 - 35.0f)));
170 this->addChild(getLabelTitle());
171 }
172
173 // 显示文本内容
174 if (getLabelContentText())
175 {
176 CCLabelTTF* ltf = getLabelContentText();
177 ltf->setPosition(ccp(winSize.width / 2, winSize.height / 2));
178 ltf->setDimensions(CCSizeMake(contentSize.width - m_contentPadding * 2, contentSize.height - m_contentPaddingTop));
179 ltf->setHorizontalAlignment(kCCTextAlignmentLeft);
180 this->addChild(ltf);
181 }
182
183 CCAction* popupLayer = CCSequence::create(CCScaleTo::create(0.0, 0.0),
184 CCScaleTo::create(0.06, 1.05),
185 CCScaleTo::create(0.08, 0.95),
186 CCScaleTo::create(0.08, 1.0), NULL);
187 this->runAction(popupLayer);
188
189 }
190
191
192 void PopupLayer::onExit()
193 {
194 CCLog("popup on exit.");
195 CCLayer::onExit();
196 }
2.测试代码
HelloWorldScene.h
1 #ifndef __HELLOWORLD_SCENE_H__
2 #define __HELLOWORLD_SCENE_H__
3
4 #include "cocos2d.h"
5
6 class HelloWorld : public cocos2d::CCLayer
7 {
8 public:
9 // Method 'init' in cocos2d-x returns bool, instead of 'id' in cocos2d-iphone (an object pointer)
10 virtual bool init();
11
12 // there's no 'id' in cpp, so we recommend to return the class instance pointer
13 static cocos2d::CCScene* scene();
14
15 // a selector callback
16 void menuCloseCallback(CCObject* pSender);
17
18 // preprocessor macro for "static create()" constructor ( node() deprecated )
19 CREATE_FUNC(HelloWorld);
20
21 void menuCallback(cocos2d::CCObject *pSender);
22 void popupLayer();
23 void buttonCallback(cocos2d::CCNode *pNode);
24 };
25
26 #endif // __HELLOWORLD_SCENE_H__
HelloWorldScene.cpp
1 #include "HelloWorldScene.h"
2 #include "SimpleAudioEngine.h"
3 #include "PopupLayer.h"
4
5 using namespace cocos2d;
6 using namespace CocosDenshion;
7
8 CCScene* HelloWorld::scene()
9 {
10 // 'scene' is an autorelease object
11 CCScene *scene = CCScene::create();
12
13 // 'layer' is an autorelease object
14 HelloWorld *layer = HelloWorld::create();
15
16 // add layer as a child to scene
17 scene->addChild(layer);
18
19 // return the scene
20 return scene;
21 }
22
23 // on "init" you need to initialize your instance
24 bool HelloWorld::init()
25 {
26 //////////////////////////////
27 // 1. super init first
28 if ( !CCLayer::init() )
29 {
30 return false;
31 }
32
33 CCSize winSize = CCDirector::sharedDirector()->getWinSize();
34 CCPoint pointCenter = ccp(winSize.width / 2, winSize.height / 2);
35
36 // 添加背景图片
37 CCSprite* background = CCSprite::create("HelloWorld.png");
38 background->setPosition(pointCenter);
39 background->setScale(1.5f);
40 this->addChild(background);
41
42 // 添加菜单
43 CCMenu* menu = CCMenu::create();
44
45 CCMenuItemFont* menuItem = CCMenuItemFont::create("popup", this, menu_selector(HelloWorld::menuCallback));
46 menuItem->setPosition(ccp(winSize.width / 2, winSize.height / 2));
47 menuItem->setColor(ccc3(0, 0, 0));
48 menu->addChild(menuItem);
49
50
51 menu->setPosition(CCPointZero);
52 this->addChild(menu);
53
54
55
56 return true;
57 }
58
59
60 void HelloWorld::menuCallback(cocos2d::CCObject *pSender){
61 popupLayer();
62 }
63
64 void HelloWorld::popupLayer()
65 {
66 // 定义一个弹出层,传入一张背景图
67 PopupLayer* pl = PopupLayer::create("useDialogBox0u00001.png");
68 // ContentSize 是可选的设置,可以不设置,如果设置把它当作 9 图缩放
69 pl->setContentSize(CCSizeMake(400, 360));
70 pl->setTitle("吾名一叶");
71 pl->setContentText("娇兰傲梅世人赏,却少幽芬暗里藏。不看百花共争艳,独爱疏樱一枝香。", 20, 50, 150);
72 // 设置回调函数,回调传回一个 CCNode 以获取 tag 判断点击的按钮
73 // 这只是作为一种封装实现,如果使用 delegate 那就能够更灵活的控制参数了
74 pl->setCallbackFunc(this, callfuncN_selector(HelloWorld::buttonCallback));
75 // 添加按钮,设置图片,文字,tag 信息
76 pl->addButton("shopBtn0s01.png", "shopBtn0s02.png", "确定", 0);
77 pl->addButton("bagButton0b1.png", "bagButton0b2.png", "取消", 1);
78 // 添加到当前层
79 this->addChild(pl);
80 }
81
82
83
84 void HelloWorld::buttonCallback(cocos2d::CCNode *pNode){
85 CCLog("button call back. tag: %d", pNode->getTag());
86 }
87
88 void HelloWorld::menuCloseCallback(CCObject* pSender)
89 {
90 CCDirector::sharedDirector()->end();
91
92 #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
93 exit(0);
94 #endif
95 }
效果图
如上,完成了对话框的基本模型,它实现了以下功能:
- 一个可以弹出的对话框实现
- 模态窗口的实现(需要逻辑的控制)
- 多按钮的支持,位置自适应,提供回调函数
- 提供标题和内容设置
- 支持 九图 ,控制适应弹出框大小
当然还有许多其它并没有照顾到的功能,或者不完善的地方,这就需要用户自己扩展,定制了,如,这样一个层,至少应该是单例的,任何时候只应该存在一个,可以用单例模式实现,对于弹出层的内容方面,这里只有标题和内容,并且标题位置固定,按钮的位置还可以更灵活的设置等。
注:
在设置按钮位置的时候有可能出现按钮位置不对,特调整如下:
1 CCMenuItemImage* itemImage = dynamic_case<CCMenuItemImage*>(array->objectAtIndex(0));
2 int count = getMenuButton()->getChildrenCount();
3 int btnWidth = itemImage->getContentSize().width;
4 int padingWidth = (contentSize.width - btnWidth * count) / (count + 1);
5 CCARRAY_FOREACH(array, obj)
6 {
7 CCNode* node = dynamic_cast<CCNode*>(obj);
8 node->setAnchorPoint(ccp(0, 0.5f));
9 node->setPosition(ccp(visibSize.width * 0.5f - contentSize.width * 0.5f + padingWidth * (i + 1) + btnWidth * i, visibSize.height * 0.5f - contentSize.height / 3));
10 i++
11 }
原文链接:http://blog.csdn.net/rexuefengye/article/details/12610909