2016年4月27日 星期三

0427 對話框教學 3

我們時常需要這麼些功能,彈出一個層,給與用戶一些提示,這也是一種模態窗口,在沒有對當前對話框進行確認的時候,不能繼續往下操作。

功能分析

我們設計一個對話框,對話框上有幾個按鈕(個數可定製),當然有個標題,會讓別人一眼看出它之功用,裡面可以有些詳細的提示文字,需要是模態窗口,而且窗口的大小可變,這樣能夠更好的適應不同的屏幕的大小。當然還有一個重要的功能,彈出效果 ~ 雖然從技術角度來說,實現起來並不難,或者說非常簡單,但這會以一個很好的用戶體驗展示給用戶。

代碼

1.彈出框類
PopupLayer.h
[cpp] view plain copy
  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
[cpp] view plain copy
  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
[cpp] view plain copy
  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
[cpp] view plain copy
  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. }  

效果圖



如上,完成了對話框的基本模型,它實現了以下功能:
  • 一個可以彈出的對話框實現
  • 模態窗口的實現(需要邏輯的控制)
  • 多按鈕的支持,位置自適應,提供回調函數
  • 提供標題和內容設置
  • 支持 九圖 ,控制適應彈出框大小
    當然還有許多其它並沒有照顧到的功能,或者不完善的地方,這就需要用戶自己擴展,定製了,如,這樣一個層,至少應該是單例的,任何時候只應該存在一個,可以用單例模式實現,對於彈出層的內容方面,這裡只有標題和內容,並且標題位置固定,按鈕的位置還可以更靈活的設置等。
詳解文章:http://www.ityran.com/archives/4854

沒有留言:

張貼留言

cocos2dx-lua 建立滑鼠監聽

重要關鍵字  EVENT_MOUSE_SCROLL addEventListenerWithSceneGraphPriority      if IsPc() then --建立滑鼠監聽         local listener = cc.EventListenerMouse...