这次要用cocos2d-x做一个可以tableview的控件,里面是一排可以下拉的按钮。这个东西在xcode上很成熟,cocos2d-x上的tableview是模仿oc写的一个控件类。
大概样子是这样的:
这里有一排可以拖动的按钮其实就是在tableview 的cell上实现。
在cocosd-x里有一个现成的例子可以用我们去看一下:
先定义一个TableViewTestLayer的类,继承CCTableViewDataSource,CCTableViewDelegate
- class TableViewTestLayer : public cocos2d::CCLayer, public cocos2d::extension::CCTableViewDataSource, public cocos2d::extension::CCTableViewDelegate
- {
- public:
- virtual bool init();
- void toExtensionsMainLayer(cocos2d::CCObject *sender);
- CREATE_FUNC(TableViewTestLayer);
- virtual void scrollViewDidScroll(cocos2d::extension::CCScrollView* view) {};
- virtual void scrollViewDidZoom(cocos2d::extension::CCScrollView* view) {}
- virtual void tableCellTouched(cocos2d::extension::CCTableView* table, cocos2d::extension::CCTableViewCell* cell);
- virtual cocos2d::CCSize cellSizeForTable(cocos2d::extension::CCTableView *table);
- virtual cocos2d::extension::CCTableViewCell* tableCellAtIndex(cocos2d::extension::CCTableView *table, unsigned int idx);
- virtual unsigned int numberOfCellsInTableView(cocos2d::extension::CCTableView *table);
- };
- CCSize winSize = CCDirector::sharedDirector()->getWinSize();
- CCTableView* tableView = CCTableView::create(this, CCSizeMake(250, 60));
- tableView->setDirection(kCCScrollViewDirectionHorizontal);
- tableView->setPosition(ccp(20,winSize.height/2-30));
- tableView->setDelegate(this);
- this->addChild(tableView);
- tableView->reloadData();
- tableView = CCTableView::create(this, CCSizeMake(60, 280));
- tableView->setDirection(kCCScrollViewDirectionVertical);
- tableView->setPosition(ccp(winSize.width-150,winSize.height/2-120));
- tableView->setDelegate(this);
- tableView->setVerticalFillOrder(kCCTableViewFillTopDown);
- this->addChild(tableView);
- tableView->reloadData();
我们看到在test中
创建了两个个tablew有水平排列和垂直排列两种形式的,并未tableview添加代理接下来,tablevie从数据源重新加载数据,并且视图将被刷新。
有了reloadData(),接下来我们就可在tableview上添加cell,并且在cell上添加一些东西。看看TableViewTestLayer里面提供了一些什么函数。
virtual void tableCellTouched(cocos2d::extension::CCTableView* table, cocos2d::extension::CCTableViewCell* cell);
virtual cocos2d::CCSize cellSizeForTable(cocos2d::extension::CCTableView *table);
virtual cocos2d::extension::CCTableViewCell* tableCellAtIndex(cocos2d::extension::CCTableView *table, unsigned int idx);
virtual unsigned int numberOfCellsInTableView(cocos2d::extension::CCTableView *table);
上面定义了4个函数,作用分别是在对应的cell上的touch事件,这里的touch事件和鼠标单击有点区别、返回每个cell的大小、通过idx在创建一个cell,可以在cell上添加一些东西、返回cell的个数。注意:第一个cell的Idx是0!
下面我们看他具体是怎么实现的
在tableView->reloadData();之后会调用函数,unsigned int TableViewTestLayer::numberOfCellsInTableView(CCTableView *table)
如果返回值大于0那么你就会执行scrollViewDidScroll()函数,返回的数值就是创建cell的个数。
- CCTableViewCell* TableViewTestLayer::tableCellAtIndex(CCTableView *table, unsigned int idx)
- {
- CCString *string = CCString::createWithFormat("%d", idx);
- CCTableViewCell *cell = table->dequeueCell();
- if (!cell) {
- cell = new CustomTableViewCell();
- cell->autorelease();
- CCSprite *sprite = CCSprite::create("Images/Icon.png");
- sprite->setAnchorPoint(CCPointZero);
- sprite->setPosition(ccp(0, 0));
- cell->addChild(sprite);
- CCLabelTTF *label = CCLabelTTF::create(string->getCString(), "Helvetica", 20.0);
- label->setPosition(CCPointZero);
- label->setAnchorPoint(CCPointZero);
- label->setTag(123);
- cell->addChild(label);
- }
- else
- {
- CCLabelTTF *label = (CCLabelTTF*)cell->getChildByTag(123);
- label->setString(string->getCString());
- }
- return cell;
- }
这个函数在tableciew上创建cell的函数,并且在对应cell上给一个与cell 的Idx值一样的label和一张图标。
CCTableViewCell *cell = table->dequeueCell(); //返回一个可使用的cell
如果cell不存在,我们手动创建一个cell。定义一个cell的类,然后将它画到对应的tableview上。
下面这个函数上面已经说过对应cell的touch函数,这里基本没写什么东西。我们touch对应cell之后会触发函数,可以用着这方法将cell做成一个按钮
void TableViewTestLayer::tableCellTouched(CCTableView* table, CCTableViewCell* cell)
{
CCLOG("cell touched at index: %i", cell->getIdx());
}
好了基本方法已经讲了,那么如何在cell上添加一个按钮呢。
一开始我是在cell上添加CCMenu,达到一个按钮的效果,可是神奇的是发生了,我发现按点下去之后竟然cell不能拖动了,这很尴尬。后来我去看了一些博客之后发现是优先级的问题,CCMenu的优先级太高了-128,我把整个cell都添加为一个按钮,所以cell的响应时间就被吞并掉了。我们如何处理这个问题呢。。。。这里有个不错的法 http://blog.csdn.net/xujiezhige/article/details/8291995
我后来用了自己的办法做。
我们转到tableview的代理类CCTableViewDelegate中,里面定义了几种响应cell的事件
class CCTableViewDelegate : public CCScrollViewDelegate
{
public:
virtual void tableCellTouched(CCTableView* table, CCTableViewCell* cell) = 0; //定义了一个touch的接口
virtual void tableCellHighlight(CCTableView* table, CCTableViewCell* cell){}; // 响应cell被按下去的函数
virtual void tableCellUnhighlight(CCTableView* table, CCTableViewCell* cell){}; //响应按下去的那个cell,按下被取消的函数
virtual void tableCellWillRecycle(CCTableView* table, CCTableViewCell* cell){}; //回收按下去的那个cell,别且从场景中删除
};
好了有这几个函数事情好办多了,我可以这样定义一个按钮:
在cell被press时,显示按钮被按下去的效果图,当点击完成后在跳转进入其他场景,如果要上下拖拉的话按下去的状态就会被取消掉。
只要在类中添加这几个函数相信聪明的各位一定能解决这个问题。
接下来我要在cell上加一个SwitchButoon,这个按钮按一下会开再按一下会关。
我们先看一下相关类CCControlSwitch
有两种创建方法
static CCControlSwitch* create(CCSprite *maskSprite, CCSprite * onSprite, CCSprite * offSprite, CCSprite * thumbSprite);
用4个精灵来创建CCControlswitch,第一个精灵是个mask,大概就是按钮的轮廓,第二个和第三个精灵对应开关开和关时的状态,第4个精灵对应你点击开关的那个按钮(可以点击也可以拖动)。
static CCControlSwitch* create(CCSprite *maskSprite, CCSprite * onSprite, CCSprite * offSprite, CCSprite * thumbSprite, CCLabelTTF* onLabel, CCLabelTTF* offLabel);
第二种多了两个Label分别对应开和关
void setOn(bool isOn);
这个函数对应初始时,开关的状态是开还是关。
virtual void setEnabled(bool enabled);
这个函数对应开关能否使用。
然后我们看一下
switchControl->addTargetWithActionForControlEvents(this, cccontrol_selector(CCControlSwitchTest::valueChanged), CCControlEventValueChanged);
addTargetWithActionForControlEvents有三个参数他们分别是
CCObject* target, SEL_CCControlHandler action, CCControlEvent controlEvents
第一个不说了,第二个就是你的点击后的回调函数在你的头文件中要以特定的参数形式定义这个函数,
void valueChanged(CCObject* sender, CCControlEvent controlEvent);
再来看看第三个参数CCControlEvent这是什么,去它的定义看一看
- enum
- {
- CCControlEventTouchDown = 1 << 0, // A touch-down event in the control.
- CCControlEventTouchDragInside = 1 << 1, // An event where a finger is dragged inside the bounds of the control.
- CCControlEventTouchDragOutside = 1 << 2, // An event where a finger is dragged just outside the bounds of the control.
- CCControlEventTouchDragEnter = 1 << 3, // An event where a finger is dragged into the bounds of the control.
- CCControlEventTouchDragExit = 1 << 4, // An event where a finger is dragged from within a control to outside its bounds.
- CCControlEventTouchUpInside = 1 << 5, // A touch-up event in the control where the finger is inside the bounds of the control.
- CCControlEventTouchUpOutside = 1 << 6, // A touch-up event in the control where the finger is outside the bounds of the control.
- CCControlEventTouchCancel = 1 << 7, // A system event canceling the current touches for the control.
- CCControlEventValueChanged = 1 << 8 // A touch dragging or otherwise manipulating a control, causing it to emit a series of different values.
- };
- typedef unsigned int CCControlEvent;
很清楚,这个枚举类型CCControlEvent
对应一系列开关事件具体的实现方式。
当你点击switch开关后调用你定义的开关函数。
valueChanged(switchControl, CCControlEventValueChanged);
CCControlSwitch* pSwitch = (CCControlSwitch*)sender;
if (pSwitch->isOn()) //开关开
{
//do something...
}
else //其他情况
{
// do something...
}
好知道了这些我们就可以高高兴兴做个按钮试试,但是很不幸又遇上了前面所说的优先级的问题,这怎么解决呢?
好在有个函数叫setDefaultTouchPriority,这是用来干什么的呢,简单的说它是调整优先级的函数,我们都知道,如果优先级越低那么它越先响应。
switchControl->setDefaultTouchPriority(-100);
添加这样一行代码再去试试。
嗯,这次很满意果断走起。
效果图:
嗯,效果实现了,下一次还要解决一些输入方面的问题和图字的使用。
刚开始学习cocos2d-x,c++也没学多久,很多东西都看不懂,有什么地方不对请大家多多指正。