cocos2dx 2.0.4 封装组合框 ComboBox

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);
}
原文地址:https://www.cnblogs.com/moodlxs/p/2837747.html