cocos2d-x 2.0.4尚未包含組合框組件,在很多需要選擇時間、道具等應用場合非常不方便,故而自己封裝了一個。基本上跟android標准組件的組合框功能和體驗都一模一樣了,而且功能更加強大, 完全可以自定義組合框的按鈕圖片,字體大小,背景圖片,按鈕高亮圖片,以及選擇列表的背景等。大小可根據設置的字體大小隨意收縮,非常方便。
先說說使用方法:
在CCLayer中要使用這個組合框,簡單的代碼如下:
ComboBox* comboBox = ComboBox::create("1985", "control/buttonBackground.png", "control/cbobtn_normal.png", "control/cbobtn_hightlight.png", "control/cellbackground.png", 60, 3); comboBox->setComboBoxDataFromContinuousInt(1900,2100); // 設置內容為1900-2100的所有數字,需要設置字符串之類的可以參考其他設置內容的接口 comboBox->setPosition(winSize.width/2, winSize.height/2); addChild(comboBox);
create()函數說明:
ComboBox::create(const char* text, const char* bgImg, const char* btnImg, const char* hightLightBtnImg, const char* cellBackGround, int fontSize, float borderPix, const char* font="Marker Felt");
text => 默認顯示的文本內容
bgImg=> 組合框背景圖片
btnImg=>組合框右邊按鈕普通狀態下的圖片
hightLightBtnImg =>組合框右邊按鈕按下狀態下的圖片
cellBackGround => 選擇列表單元格的背景圖片
fontSize => 字體大小,決定組合框的大小
borderPix => 圖片邊界尺寸,因為圖片需要隨着組合框縮放,故需要邊界尺寸,這個具體可以看看CCScale9Sprite的原理,相當於rectInsets的內容
font => 字體樣式
附上截圖:
組合框樣子: 點擊按鈕彈出選擇列表
附上源代碼:
注意,源代碼中,MyTableView的實現在我的另外一篇文章中,主要就是修復了CCTableView中不能點擊的bug,文章見這里:cocos2d-x 2.0.4 CCTableView 點擊無響應問題.
ComboBox.h
#ifndef __COMBOBOX_H__ #define __COMBOBOX_H__ #include "cocos2d.h" #include "cocos-ext.h" #include "MyTableView.h" #include <vector> USING_NS_CC; USING_NS_CC_EXT; typedef std::vector<std::string> ComboBoxDataList; class ComboBoxTableViewLayer; class ComboBox : public CCLayer { public: ComboBox(); virtual ~ComboBox(); bool init(const char* text, const char* bgImg, const char* btnImg, const char* hightLightBtnImg, const char* cellBackGround, int fontSize, float borderPix, const char* font); static ComboBox* create(const char* text, const char* bgImg, const char* btnImg, const char* hightLightBtnImg, const char* cellBackGround, int fontSize, float borderPix, const char* font="Marker Felt"); bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent); void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent); void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent); void ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent); void touchUpInside(CCObject* pSender, CCControlEvent event); void setComboBoxDataList(const ComboBoxDataList& dataList) ; void setComboBoxDataFromContinuousInt(int start, int end, int step=1); void setComboBoxDataFromContinuousFloat(float start, float end, float step=1.0); void clearDataList(); const char* getLabel(); void setLabel(const char* label); protected: void setContentSize(const CCSize& s); protected: CCLabelTTF* m_label; CCControlButton* m_button; CCScale9Sprite* m_backGround; ComboBoxTableViewLayer* m_tableViewLayer; ComboBoxDataList m_dataList; const char* m_cellBackGround; const char* m_font; float m_borderPix; float m_fontSize; }; class ComboBoxTableViewLayer : public CCLayer, public CCTableViewDataSource, public CCTableViewDelegate { public: ComboBoxTableViewLayer(); ~ComboBoxTableViewLayer(); virtual bool init(ComboBoxDataList* dataList, const char* cellBackGround, float borderPix, float fontSize, const char* font); static ComboBoxTableViewLayer* create(ComboBox* frame, ComboBoxDataList* dataList, const char* cellBackGround, float borderPix, float fontSize, const char* font); void reloadDataList(); MyTableView* getTableView() { return m_tableView; } virtual void scrollViewDidScroll(CCScrollView* view) {}; virtual void scrollViewDidZoom(CCScrollView* view) {} virtual void tableCellTouched(CCTableView* table, CCTableViewCell* cell); virtual CCSize cellSizeForTable(CCTableView *table); virtual CCTableViewCell* tableCellAtIndex(CCTableView *table, unsigned int idx); virtual unsigned int numberOfCellsInTableView(CCTableView *table); void setFrame(ComboBox* frame) { m_frame = frame;} bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent); void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent); void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent); void ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent); void onEnter(); void onExit(); protected: const char* m_cellBackGround; float m_borderPix; float m_fontSize; const char* m_font; CCRect m_backGroundRect; CCRect m_backGroundRectInsets; ComboBoxDataList* m_dataList; MyTableView* m_tableView; ComboBox* m_frame; }; #endif
ComboBox.cpp:
#include "ComboBox.h" ComboBox::ComboBox() :m_label(NULL), m_button(NULL), m_backGround(NULL), m_tableViewLayer(NULL) { } ComboBox::~ComboBox() { if (m_label) { m_label->release(); } if (m_button) { m_button->release(); } if (m_backGround) { m_backGround->release(); } if (m_tableViewLayer) { m_tableViewLayer->release(); } } ComboBox* ComboBox::create(const char* text, const char* bgImg, const char* btnImg, const char* hightLightBtnImg, const char* cellBackGround, int fontSize, float border, const char* font ) { ComboBox* comboBox = new ComboBox(); if (comboBox && comboBox->init(text, bgImg, btnImg, hightLightBtnImg, cellBackGround, fontSize, border, font)) { comboBox->autorelease(); return comboBox; } else { delete comboBox; return NULL; } } const char* ComboBox::getLabel() { return m_label->getString(); } void ComboBox::setLabel(const char* label) { m_label->setString(label); } bool ComboBox::init(const char* text, const char* bgImg, const char* btnImg, const char* hightLightBtnImg, const char* cellBackGround, int fontSize, float borderPix, const char* font) { m_cellBackGround = cellBackGround; m_borderPix = borderPix; m_fontSize = (float)fontSize; m_font = font; if (!CCLayer::init()) { return false; } // 支持AnchorPoint定位, 默認情況下Layer不支持 ignoreAnchorPointForPosition(false); // 支持觸屏 setTouchEnabled(true); // 創建Label CCSize size; m_label = CCLabelTTF::create(text, font, fontSize); if (!m_label) return false; m_label->setPosition(ccp(m_label->getContentSize().width/2, m_label->getContentSize().height/2)); m_label->retain(); addChild(m_label, 1); size = m_label->getContentSize(); // 創建按鈕 float space = 3; /// 由於按鈕圖片可能是大圖片,需要收縮,所以采用三個參數的create,需要先獲取圖片大小 CCSprite* tsp = CCSprite::create(btnImg); CCSize s = tsp->getContentSize(); CCRect imgRect = CCRectMake(0,0, s.width, s.height); CCRect imgRectInsets = CCRectMake(borderPix, borderPix, s.width-2*borderPix, s.height-2*borderPix); tsp->release(); CCScale9Sprite *backgroundButton = CCScale9Sprite::create(btnImg, imgRect, imgRectInsets); CCScale9Sprite *backgroundHighlightedButton = CCScale9Sprite::create(hightLightBtnImg, imgRect, imgRectInsets); m_button = CCControlButton::create(backgroundButton); m_button->setZoomOnTouchDown(false); m_button->setBackgroundSpriteForState(backgroundHighlightedButton, CCControlStateHighlighted); m_button->setPreferredSize(CCSizeMake(size.height, size.height)); m_button->setPosition(m_label->getContentSize().width + m_button->getContentSize().width/2 + space, m_button->getContentSize().height/2); m_button->addTargetWithActionForControlEvents(this, cccontrol_selector(ComboBox::touchUpInside), CCControlEventTouchUpInside); m_button->retain(); addChild(m_button, 1); size.width += m_button->getContentSize().width + space; if (m_button->getContentSize().height > size.height) { size.height = m_button->getContentSize().height; } // 創建背景, 背景圖片正常都是拉伸,用一個參數的create夠了,如果背景還搞大圖片,那就不能怪我了。。。 m_backGround = CCScale9Sprite::create(bgImg); m_backGround->setPreferredSize(size); m_backGround->setPosition(ccp(m_backGround->getContentSize().width/2, m_backGround->getContentSize().height/2)); m_backGround->retain(); addChild(m_backGround, 0); this->setContentSize(size); //m_tableViewLayer = ComboBoxTableViewLayer::create(&m_dataList, cellBackGround, borderPix, (float)fontSize, font); //m_tableViewLayer->retain(); } void ComboBox::setComboBoxDataList(const ComboBoxDataList& dataList) { m_dataList = dataList; } void ComboBox::setComboBoxDataFromContinuousInt(int start, int end, int step) { char buf[50]; for (int i=start; i <= end; i+=step) { sprintf(buf, "%d", i); m_dataList.push_back(buf); } } void ComboBox::setComboBoxDataFromContinuousFloat(float start, float end, float step) { char buf[50]; for (float i=start; i <= end; i+=step) { sprintf(buf, "%f", i); m_dataList.push_back(buf); } } void ComboBox::clearDataList() { m_dataList.clear(); } void ComboBox::setContentSize(const CCSize& s) { CCLayer::setContentSize(s); } bool ComboBox::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent) { CCPoint p = m_button->getPosition(); p.x+=1; p.y+=1; pTouch->setTouchInfo(pTouch->getID(), p.x, p.y); m_button->ccTouchBegan(pTouch, pEvent); return true; // 屏蔽該消息不往下傳遞 } void ComboBox::ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent) { CCPoint p = m_button->getPosition(); p.x+=1; p.y+=1; pTouch->setTouchInfo(pTouch->getID(), p.x, p.y); m_button->ccTouchMoved(pTouch, pEvent); } void ComboBox::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent) { CCPoint p = m_button->getPosition(); p.x+=1; p.y+=1; pTouch->setTouchInfo(pTouch->getID(), p.x, p.y); m_button->ccTouchEnded(pTouch, pEvent); } void ComboBox::ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent) { CCPoint p = m_button->getPosition(); p.x+=1; p.y+=1; pTouch->setTouchInfo(pTouch->getID(), p.x, p.y); m_button->ccTouchEnded(pTouch, pEvent); } void ComboBox::touchUpInside(CCObject* pSender, CCControlEvent event) { CCLog("touchUpInside"); CCSize winSize = CCDirector::sharedDirector()->getWinSize(); float fontSize = (float)m_fontSize/2; if (fontSize < 20) { fontSize = 20; } ComboBoxTableViewLayer* layer = ComboBoxTableViewLayer::create(this, &m_dataList, m_cellBackGround, m_borderPix, fontSize, m_font); layer->setAnchorPoint(ccp(0.5,0.5)); layer->setPosition(ccp(winSize.width/2, winSize.height/2)); CCScene* curScene = CCDirector::sharedDirector()->getRunningScene(); int cnt = curScene->getChildrenCount(); CCLog("cnt=%d", cnt); curScene->addChild(layer, cnt+15); } ComboBoxTableViewLayer::ComboBoxTableViewLayer() :m_tableView(NULL) { } ComboBoxTableViewLayer::~ComboBoxTableViewLayer() { CC_SAFE_RELEASE(m_tableView); } ComboBoxTableViewLayer* ComboBoxTableViewLayer::create(ComboBox* frame, ComboBoxDataList* dataList, const char* cellBackGround, float borderPix, float fontSize, const char* font) { ComboBoxTableViewLayer* layer = new ComboBoxTableViewLayer(); if (layer && layer->init(dataList, cellBackGround, borderPix, fontSize, font)) { layer->setFrame(frame); layer->autorelease(); return layer; }else { CC_SAFE_DELETE(layer); return NULL; } } bool ComboBoxTableViewLayer::init(ComboBoxDataList* dataList, const char* cellBackGround, float borderPix, float fontSize, const char* font) { m_dataList = dataList; m_cellBackGround = cellBackGround; m_borderPix = borderPix; m_fontSize = fontSize; m_font = font; CCLog("ComboBoxTableViewLayer, cellBackGround=%s, borderPix=%f, fontSize=%f, font=%s", m_cellBackGround, m_borderPix, m_fontSize, m_font); if ( !CCLayer::init() ) { return false; } /// 支持錨點 ignoreAnchorPointForPosition(false); // 先保存圖片的大小 CCSprite* tps = CCSprite::create(cellBackGround); CCSize s = tps->getContentSize(); m_backGroundRect = CCRectMake(0,0, s.width, s.height); m_backGroundRectInsets = CCRectMake(m_borderPix, m_borderPix, s.width-2*m_borderPix, s.height-2*m_borderPix); tps->release(); CCSize winSize = CCDirector::sharedDirector()->getWinSize(); CCSize contentSize = CCSizeMake(winSize.width*0.9, winSize.height*0.9); m_tableView = MyTableView::create(this, contentSize); m_tableView->setDirection(kCCScrollViewDirectionVertical); m_tableView->setDelegate(this); m_tableView->setVerticalFillOrder(kCCTableViewFillTopDown); m_tableView->reloadData(); m_tableView->retain(); this->addChild(m_tableView); setContentSize(contentSize); CCSize sx = getContentSize(); CCLog("cctt.w,h:%f,%f", sx.width, sx.height); return true; } void ComboBoxTableViewLayer::tableCellTouched(CCTableView* table, CCTableViewCell* cell) { CCLog("cell touched at index: %i", cell->getIdx()); const char* name = ((CCLabelTTF*)(cell->getChildByTag(123)))->getString(); m_frame->setLabel(name); this->removeFromParentAndCleanup(true); } CCSize ComboBoxTableViewLayer::cellSizeForTable(CCTableView *table) { CCSize contentSize = getContentSize(); return CCSizeMake(contentSize.width, m_fontSize+15); } CCTableViewCell* ComboBoxTableViewLayer::tableCellAtIndex(CCTableView *table, unsigned int idx) { std::string str = (*m_dataList)[idx]; CCTableViewCell *cell = table->dequeueCell(); if (!cell) { CCLog("add str:%s", str.c_str()); CCSize s = cellSizeForTable(NULL); cell = new CCTableViewCell(); cell->autorelease(); CCScale9Sprite* backGround = CCScale9Sprite::create(m_cellBackGround, m_backGroundRect, m_backGroundRectInsets); backGround->setContentSize(s); backGround->setPosition(CCPointZero); backGround->setAnchorPoint(CCPointZero); cell->addChild(backGround, 0); CCLabelTTF *label = CCLabelTTF::create(str.c_str(), m_font, m_fontSize); label->setPosition(CCPointZero); label->setAnchorPoint(CCPointZero); label->setTag(123); cell->addChild(label, 1); } else { CCLabelTTF *label = (CCLabelTTF*)cell->getChildByTag(123); label->setString(str.c_str()); } return cell; } unsigned int ComboBoxTableViewLayer::numberOfCellsInTableView(CCTableView *table) { return m_dataList->size(); } void ComboBoxTableViewLayer::reloadDataList() { m_tableView->reloadData(); } bool ComboBoxTableViewLayer::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent) { m_tableView->ccTouchBegan(pTouch, pEvent); return true; } void ComboBoxTableViewLayer::ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent) { m_tableView->ccTouchMoved(pTouch, pEvent); } void ComboBoxTableViewLayer::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent) { m_tableView->ccTouchEnded(pTouch, pEvent); } void ComboBoxTableViewLayer::ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent) { m_tableView->ccTouchEnded(pTouch, pEvent); } void ComboBoxTableViewLayer::onEnter() { CCLayer::onEnter(); CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, -129, true); } void ComboBoxTableViewLayer::onExit() { CCLayer::onExit(); CCDirector::sharedDirector()->getTouchDispatcher()->removeDelegate(this); }