在引擎中并没有提供相应的下拉列表控件实现,所以如果在实际应用中需要的话就要自己代码实现。
下面我介绍两种实现的方式,以供大家参考。
方法一:
这个方法我是参考了网上的一段代码,然后自己对代码进行部分的修改,下面贴出一个xcode中的下拉列表框样式:
下面先贴出自定义实现的效果图:
通常,一个下拉列表框都是这样的:
①有一个选中后的显示栏目;
②点击显示栏目后,显示下拉列表,选中的哪一个行会高亮显示;
③对下拉列表进行选择,选好后,下拉列表会消失,显示栏目显示选中的内容。
下面先贴出实现的代码:
#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中的一个样式:
下面给出自定义实现的效果图:(图一)
点击后,弹出列表框:(图二)
选中第二行后:(图三)
大致样式还是差不多的吧,下面讲述一下如何实现的吧!
总体实现思路:
①这对第一个图(图一),其实就是一个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()); }
#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);