Cocos2d-x 自定义实现下拉列表框(两种实现方法)

在引擎中并没有提供相应的下拉列表控件实现,所以如果在实际应用中需要的话就要自己代码实现。

  下面我介绍两种实现的方式,以供大家参考。


方法一:

这个方法我是参考了网上的一段代码,然后自己对代码进行部分的修改,下面贴出一个xcode中的下拉列表框样式:

Cocos2d-x 自定义实现下拉列表框(两种实现方法)_第1张图片

下面先贴出自定义实现的效果图:

Cocos2d-x 自定义实现下拉列表框(两种实现方法)_第2张图片

通常,一个下拉列表框都是这样的:

①有一个选中后的显示栏目;

②点击显示栏目后,显示下拉列表,选中的哪一个行会高亮显示;

③对下拉列表进行选择,选好后,下拉列表会消失,显示栏目显示选中的内容。


下面先贴出实现的代码:

#ifndef DropDownListBox_DROPDOWNLIST_h
#define DropDownListBox_DROPDOWNLIST_h

USING_NS_CC;

namespace CustomDropDownListBox
{
    //设置背景颜色
#define DROPDOWNLIST_NORMAL_COLOR       ccc4(128, 128, 128, 255)
#define DROPDOWNLIST_SELECTED_COLOR     ccc4(200, 200, 200, 255)
#define DROPDOWNLIST_HIGHLIGHT_COLOR    ccc4(0, 0, 255, 255)
    
#define DROPDOWNLIST_NORMAL_COLOR3       ccc3(128, 128, 128)
#define DROPDOWNLIST_SELECTED_COLOR3     ccc3(200, 200, 200)
#define DROPDOWNLIST_HIGHLIGHT_COLOR3    ccc3(0, 0, 255)
    
    class DropDownList : public CCLayer
    {
    public:
        //构造方法
        DropDownList(CCLabelTTF* label, CCSize size)
        : showLabel(label)
        , isShowMenu(false)
        , lastSelectedIndex(0)
        {
            //创建好一个menu,但是现在还不添加到视图中
            mainMenu = CCMenu::create();
            mainMenu->setPosition(CCPoint(size.width / 2, size.height / 2));
            mainMenu->retain();
            
            showLabel->setPosition(CCPoint(size.width / 2, size.height / 2));
            addChild(showLabel);
            
            setContentSize(size);
        }
        
        //析构函数
        ~DropDownList()
        {
            mainMenu->release();
        }
        
        //创建实例对象方法
        static DropDownList* create(CCLabelTTF* label, CCSize size)
        {
            DropDownList* list = new DropDownList(label, size);
            list->autorelease();
            return list;
        }
        //获取当前选中label的string
        std::string getString()
        {
            return showLabel->getString();
        }
        
        //获取当前选中的index
        int getSelectedIndex()
        {
            return lastSelectedIndex;
        }
        
        //设置选中index
        void setSelectedIndex(int index)
        {
            lastSelectedIndex = index;
            
            for (int i = 0, j = (int)selectLabels.size(); i < j; ++i)
            {
                if (i == lastSelectedIndex)
                {
                    bgLayers[i]->setColor(DROPDOWNLIST_HIGHLIGHT_COLOR3);
                    showLabel->setString(selectLabels[i]->getString());
                }
                else
                {
                    bgLayers[i]->setColor(DROPDOWNLIST_NORMAL_COLOR3);
                }
            }
        }
        
        void onEnter()
        {
            setTouchEnabled(true);
            CCLayer::onEnter();
        }
        
        void registerWithTouchDispatcher()
        {
            CCDirector* pDirector = CCDirector::sharedDirector();
            pDirector->getTouchDispatcher()->addTargetedDelegate(this, kCCMenuHandlerPriority, true);
        }
        
        virtual bool ccTouchBegan(CCTouch *touch, CCEvent *event)
        {
            if (!isShowMenu)
            {
                CCRect rect;
                rect.origin = CCPointZero;
                rect.size = getContentSize();
                CCPoint position = convertTouchToNodeSpace(touch);
                
                if (rect.containsPoint(position))
                {
                    isShowMenu = true;
                    
                    //点击,显示下拉列表框,也就是mainMenu
                    addChild(mainMenu);
                    
                    for (int i = 0, j = (int)selectLabels.size(); i < j; ++i)
                    {
                        if (i == lastSelectedIndex)
                        {
                            bgLayers[i]->setColor(DROPDOWNLIST_HIGHLIGHT_COLOR3);
                        }
                        else
                        {
                            bgLayers[i]->setColor(DROPDOWNLIST_NORMAL_COLOR3);
                        }
                    }
                    

                    
                    return true;
                }
            }
            
            return false;
        }
        
        //创建以menu item 并添加一个label覆盖到上面
        void addLabel(CCLabelTTF* label)
        {
            CCSize size = getContentSize();
            
            CCLayerColor* normal   = CCLayerColor::create(DROPDOWNLIST_NORMAL_COLOR, size.width, size.height);
            CCLayerColor* selected = CCLayerColor::create(DROPDOWNLIST_SELECTED_COLOR, size.width, size.height);
            
            bgLayers.push_back(normal);
            
            selectLabels.push_back(label);
            
            CCMenuItem* item = CCMenuItemSprite::create(
                                                                          normal,
                                                                          selected,
                                                                          NULL,
                                                                          this,
                                                                          SEL_MenuHandler(&DropDownList::onSelected)
                                                                          );
            
            label->setPosition(CCPoint(size.width / 2, size.height / 2));
            item->addChild(label);
            item->setTag((int)selectLabels.size() - 1);
            item->setPosition(0, - (int)selectLabels.size() * size.height);
            
            mainMenu->addChild(item);
            
        }
        
        //选中下拉列表后
        void onSelected(CCObject* sender)
        {
            CCMenuItem* item = dynamic_cast<CCMenuItem*>(sender);
            if (item)
            {
                lastSelectedIndex = item->getTag();
                showLabel->setString(selectLabels[item->getTag()]->getString());
            }
            onClose(); //关闭下拉列表框
        }
        
        //关闭下拉列表框
        void onClose()
        {
            removeChild(mainMenu, true);  //通过删除mainMenu,关闭下拉列表框
            isShowMenu = false;
        }
        
    private:
        CCMenu* mainMenu;  //下拉列表选项的集合
        
        CCLabelTTF* showLabel;  //显示选中的结果
        
        std::vector<CCLabelTTF*> selectLabels;  //下拉列表label
        
        std::vector<CCLayerColor*> bgLayers; //用于设置 背景
        
        bool isShowMenu;  //是否显示了下拉列表
        
        int lastSelectedIndex;  //选中下拉列表的index

    };
    
}

#endif

下面简单解释一下其中的实现:

①其中显示栏目是一个label,在代码中就是showLable。

②其中的下拉列表是一个menu,在创建该下拉列表框对象的时候,会创建menu对象,但是不添加;当点击touch的时候,在began方法中才添加。也就是说,点击之后,才显示下拉列表框。

③下拉列表中的每一行都是一个menu item,点击选择后,会触发 void onSelected(CCObject* sender) 方法,并且关闭下拉列表,关闭下拉列表的是 void onClose() 方法,实际就是将menu删除。

④下面简单罗列一下代码中提供的接口吧:

//创建实例对象方法
        static DropDownList* create(CCLabelTTF* label, CCSize size)

//获取当前选中label的string
        std::string getString()

//获取当前选中的index
        int getSelectedIndex()

//设置选中index
        void setSelectedIndex(int index)

下面看看,如何使用的代码:

  //创建显示栏目的label
    CCLabelTTF* initLabel = CCLabelTTF::create("hello", "Arial", 22);
    //设置显示栏目的size
    CCSize size = CCSizeMake(80,30);
    //创建下拉列表框对象
    CustomDropDownListBox::DropDownList* listBox = CustomDropDownListBox::DropDownList::create(initLabel,size);
    
    //向下拉列表添加三个选项
    CCLabelTTF* label1 = CCLabelTTF::create("hello", "Arial", 22);
    listBox->addLabel(label1);
    
    
    CCLabelTTF* label2 = CCLabelTTF::create("world", "Arial", 22);
    listBox->addLabel(label2);
    
    CCLabelTTF* label3 = CCLabelTTF::create("demo", "Arial", 22);
    listBox->addLabel(label3);

    //设置下拉列表框默认选项,默认是第0项
//    listBox->setSelectedIndex(0);
    
    listBox->setPosition(20,300);
    this->addChild(listBox,2);

很简单吧!就不多说了 吐舌头


方法二:

这个是另一种样式的下拉列表框,下面同样给出xoode中的一个样式:

Cocos2d-x 自定义实现下拉列表框(两种实现方法)_第3张图片      Cocos2d-x 自定义实现下拉列表框(两种实现方法)_第4张图片

下面给出自定义实现的效果图:(图一)

Cocos2d-x 自定义实现下拉列表框(两种实现方法)_第5张图片

点击后,弹出列表框:(图二)

Cocos2d-x 自定义实现下拉列表框(两种实现方法)_第6张图片

选中第二行后:(图三)

Cocos2d-x 自定义实现下拉列表框(两种实现方法)_第7张图片

大致样式还是差不多的吧,下面讲述一下如何实现的吧!

总体实现思路:

①这对第一个图(图一),其实就是一个menu,上面添加了一个label。

②点击了这个menu之后,就会出来一个列表,这个其实是一个自定义实现的sprite,而且可接收触摸消息。那么在对一行行的选项进行选择的时候就可以进行触摸检测,从而判断出是选中了哪一个行。

注意:由于图一中显示的是一个menu,那么其接收触摸消息的优先级是很高的,是 kCCMenuHandlerPriority,那么为了让menu上面的这个列表可以接收到触摸消息,那么其优先级级要比menu高,也就是 kCCMenuHandlerPriority-1

关于自定义sprite接收触摸消息的内容参考我的这篇博文:点击打开链接

③选择之后,通过Notification通知,对显示的label值进行修改。


下面展示一下代码吧:

DropDownListSprite 下拉列表框类:

#ifndef __DropDownListBox__DropDownListSprite__
#define __DropDownListBox__DropDownListSprite__

#include <iostream>
#include "cocos2d.h"
#include "SelectedBoxSprite.h"

USING_NS_CC;
class DropDownListSprite:public CCSprite
{
public:
    DropDownListSprite();
    ~DropDownListSprite();
    
    static DropDownListSprite* createMyList(const char *pszFilename);
    
    void hello();
    
private:
    bool setUpSprite();
    void dropDownMenuCallBack(CCObject* pObject);
    
    //通知中心的回调方法
    void myNotificationFunc(CCObject* obj);
    CCLabelTTF* label;
};
#endif /* defined(__DropDownListBox__DropDownListSprite__) */

#include "DropDownListSprite.h"

#define MyNotification "DidSelectIndex"

DropDownListSprite::DropDownListSprite()
{
    
}

DropDownListSprite::~DropDownListSprite()
{
    CCNotificationCenter::sharedNotificationCenter()->removeObserver(this, MyNotification);
}

DropDownListSprite* DropDownListSprite::createMyList(const char *pszFilename)
{
    DropDownListSprite* ddlSprite = new DropDownListSprite();
    if (ddlSprite && ddlSprite->initWithFile(pszFilename) && ddlSprite->setUpSprite()) {
        ddlSprite->autorelease();
        return ddlSprite;
    }
    CC_SAFE_DELETE(ddlSprite);
    return NULL;
}

bool DropDownListSprite::setUpSprite()
{
    bool pRet = false;
    do {
        
        CCMenuItemImage* itemImage = CCMenuItemImage::create("box.png", "box_clik.png", this, menu_selector(DropDownListSprite::dropDownMenuCallBack));
        itemImage->setTag(1);
        CCMenu* menu = CCMenu::create(itemImage,NULL);
        itemImage->setAnchorPoint(CCPointZero);
        menu->setPosition(CCPointZero);
        this->addChild(menu);
        
        label = CCLabelTTF::create("Select Number", "Arial", 20);
        label->setColor(ccBLACK);
        label->setAnchorPoint(CCPointZero);
        label->setPosition(ccpAdd(CCPointZero, ccp(10, 1)));
        this->addChild(label);
        
        SelectedBoxSprite* selectBoxSprite = SelectedBoxSprite::createWithPic("list_box.png");
        selectBoxSprite->setAnchorPoint(ccp(0.5, 0.5));
        selectBoxSprite->setPosition(ccp(60, 15));
        selectBoxSprite->setTag(2);
        this->addChild(selectBoxSprite,1);
        selectBoxSprite->setVisible(false);
        
        CCNotificationCenter::sharedNotificationCenter()->addObserver(this, callfuncO_selector(DropDownListSprite::myNotificationFunc), MyNotification, NULL);
        
        pRet = true;
    } while (0);
    return pRet;
}

void DropDownListSprite::dropDownMenuCallBack(CCObject* pObject)
{
    SelectedBoxSprite* sprite = (SelectedBoxSprite*)this->getChildByTag(2);
    
    if (!sprite->isVisible()) {
        sprite->setVisible(true);
        CCFadeIn* fadeIn = CCFadeIn::create(0.3);
        sprite->runAction(fadeIn);
    }
    
}

void DropDownListSprite::myNotificationFunc(cocos2d::CCObject *obj)
{
    int tag = (int)obj;
    CCLOG("did select tag = %d",tag);
    CCString* string = CCString::createWithFormat("Select :%d",tag);
    label->setString(string->getCString());
}


SelectedBoxSprite 弹出列表类(自定义精灵类)
#ifndef __DropDownListBox__SelectedBoxSprite__
#define __DropDownListBox__SelectedBoxSprite__

#include <iostream>
#include "cocos2d.h"

USING_NS_CC;

class SelectedBoxSprite : public CCSprite,public CCTargetedTouchDelegate
{
public:
    SelectedBoxSprite();
    ~SelectedBoxSprite();
    
    static SelectedBoxSprite* createWithPic(const char* name);
    bool setUpdateView();
    
    virtual void onEnter();
    virtual void onExit();
    
    virtual bool ccTouchBegan(CCTouch *touch, CCEvent *event);
    virtual void ccTouchMoved(CCTouch *touch, CCEvent *event);
    virtual void ccTouchEnded(CCTouch *touch, CCEvent *event);
    
    CCRect rect();
    bool containsTouchLocation(CCTouch *touch);
    
private:
    CCArray* listSpriteArray;
    
    //点击了列表框后的回调方法,让点击的那一行闪烁
    void didSelectCallBack(CCObject* obj);
    void didSelectCallBack_1();
    
};
#endif /* defined(__DropDownListBox__SelectedBoxSprite__) */


#include "SelectedBoxSprite.h"
#include "CCProtocols.h"

#define MyNotification "DidSelectIndex"

SelectedBoxSprite::SelectedBoxSprite()
{
    listSpriteArray = CCArray::create();
    listSpriteArray->retain();
}

SelectedBoxSprite::~SelectedBoxSprite()
{
    listSpriteArray->release();
}

SelectedBoxSprite* SelectedBoxSprite::createWithPic(const char *name)
{
    SelectedBoxSprite* pobView = new SelectedBoxSprite();
    if (pobView && pobView->initWithFile(name) && pobView->setUpdateView()) {
        pobView->autorelease();
        return pobView;
    }
    CC_SAFE_DELETE(pobView);
    return NULL;
}

bool SelectedBoxSprite::setUpdateView()
{
    bool isRet = false;
    do {
        this->setCascadeOpacityEnabled(true);
        
        CCSprite* spr1 = CCSprite::create("yellow.png");
        spr1->setAnchorPoint(CCPointZero);
        spr1->setTag(1);
        spr1->setPosition(ccp(0, 4));
        this->addChild(spr1);
        
        listSpriteArray->addObject(spr1);

        CCSprite* spr2 = CCSprite::create("yellow_1.png");
        spr2->setAnchorPoint(CCPointZero);
        spr2->setTag(2);
        spr2->setPosition(ccp(0, 30));
        this->addChild(spr2);
        
        listSpriteArray->addObject(spr2);
        
        isRet = true;
    } while (0);
    return isRet;
}


void SelectedBoxSprite::onEnter()
{
    CCSprite::onEnter();
    CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, kCCMenuHandlerPriority-1, true);
}

void SelectedBoxSprite::onExit()
{
    
    CCSprite::onExit();
    CCDirector::sharedDirector()->getTouchDispatcher()->removeDelegate(this);
}

CCRect SelectedBoxSprite::rect()
{
    CCSize size = getTexture()->getContentSize();    
    return CCRectMake(-size.width / 2, -size.height / 2, size.width, size.height);
}

bool SelectedBoxSprite::containsTouchLocation(cocos2d::CCTouch *touch)
{
    CCRect my = rect();
    CCPoint p = convertTouchToNodeSpaceAR(touch);    
    return my.containsPoint(p);
}

bool SelectedBoxSprite::ccTouchBegan(cocos2d::CCTouch *touch, cocos2d::CCEvent *event)
{
    bool bRet = false;
    if (this->isVisible()) { //注意要在列表框可视化的情况下再作处理
        
        if (containsTouchLocation(touch))
        {
            this->setVisible(true);
            
            CCLog("Touchable Sprite Began");
            
            CCPoint point = convertTouchToNodeSpace(touch);
            CCObject* obj = NULL;
            CCARRAY_FOREACH(listSpriteArray, obj)
            {
                CCSprite* sprite = dynamic_cast<CCSprite*>(obj);
                if (sprite->boundingBox().containsPoint(point)) {
                    //这里表示点击到某一个list
                    
                    // CCLog("tag = %d",sprite->getTag());
                    
                    //发送选择的那一行的tag,并且消失列表框
                    CCSprite* selectedSprite = (CCSprite*)this->getChildByTag(sprite->getTag());
                    CCBlink* blink = CCBlink::create(0.2, 3);
                    selectedSprite->runAction(CCSequence::create(blink,
                                                                 CCCallFuncO::create(this, callfuncO_selector(SelectedBoxSprite::didSelectCallBack), (CCObject*)selectedSprite),
                                                                 NULL));
                    
                    
                    
                    
                    break;
                }
            }
                    
            bRet = true;
        }
        else
        {
            CCFadeOut* fadeout = CCFadeOut::create(0.3);
            this->runAction(fadeout);
            this->runAction(CCSequence::create(fadeout,CCCallFunc::create(this, callfunc_selector(SelectedBoxSprite::didSelectCallBack_1)),NULL));
        }
    }
    
    return bRet;
}

void SelectedBoxSprite::didSelectCallBack(CCObject* obj)
{
    CCSprite* spri = (CCSprite*)obj;
    CCNotificationCenter::sharedNotificationCenter()->postNotification(MyNotification, (CCObject*)spri->getTag());
    
    CCFadeOut* fadeout = CCFadeOut::create(0.3);
    this->runAction(fadeout);
    this->runAction(CCSequence::create(fadeout,CCCallFunc::create(this, callfunc_selector(SelectedBoxSprite::didSelectCallBack_1)),NULL));

}
void SelectedBoxSprite::didSelectCallBack_1()
{
    this->setVisible(false);
}

void SelectedBoxSprite::ccTouchMoved(cocos2d::CCTouch *touch, cocos2d::CCEvent *event)
{
    if (containsTouchLocation(touch))
    {
//        CCLog("Touchable Sprite Moved");
    }
}

void SelectedBoxSprite::ccTouchEnded(cocos2d::CCTouch *touch, cocos2d::CCEvent *event)
{
    if (containsTouchLocation(touch))
    {
//        CCLog("Touchable Sprite Ended");
    }
}


下面贴一下如何使用的代码:

DropDownListSprite* sprite = DropDownListSprite::createMyList("box.png");
    sprite->setPosition(ccp(300, 350));
    this->addChild(sprite);


关于这个下拉列表框的实现,我只是大致实现了一个模型,其中列表框出现和隐藏都使用了CCFade~动作,点击选择某一列后,会闪烁提示,有着较好的交互效果。当然,其中的接口还没有太写好,有需要的自己再改进一下应该可以用的。 大笑



你可能感兴趣的:(cocos2d-x,下拉列表框,自定义实现)