zoukankan      html  css  js  c++  java
  • cocos2d-x学习日志(12) --弹出对话框的设计与实现

    我们时常需要这么些功能,弹出一个层,给与用户一些提示,这也是一种模态窗口,在没有对当前对话框进行确认的时候,不能继续往下操作。


    功能分析

    我们设计一个对话框,对话框上有几个按钮(个数可定制),当然有个标题,会让别人一眼看出它之功用,里面可以有些详细的提示文字,需要是模态窗口,而且窗口的大小可变,这样能够更好的适应不同的屏幕的大小。当然还有一个重要的功能,弹出效果 ~ 虽然从技术角度来说,实现起来并不难,或者说非常简单,但这会以一个很好的用户体验展示给用户。

    代码

    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

     

    //
    //  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();
    }
    


    2.测试代码

    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__


    HelloWorldScene.cpp

     

    #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

  • 相关阅读:
    HTTP协议
    idea新建工程项目结构
    idea使用的JDK版本1.9换成1.8后相关的更改设置
    Servlet
    Tomcat三种项目部署方式
    Tomcat环境变量配置命令行报错:The JRE_HOME environment variable is not defined correctl This environment variable is needed to run this program
    JDBC面试题
    XML基础入门
    数据库连接池——Druid
    $.ajax 分页
  • 原文地址:https://www.cnblogs.com/riasky/p/3363599.html
Copyright © 2011-2022 走看看