cocos2dx基础篇(17)——列表视图CCTableView
【唠叨】
关于CCTableView的知识,网上很多大牛都写得很详细了,我也是看他们的博客进行学习的。所以在这里我只讲讲个人的学习心得,以及对CCTableView使用方法的总结。
注:因为大牛讲得都太详细了,所以本节中有些知识的介绍可能摘自各位大牛的博客。
【致谢】
http://www.zaojiahua.com/cctableview.html
http://blog.csdn.net/u012945598/article/details/20901645
【Demo下载】
https://github.com/shahdza/Cocos_LearningTest/tree/master/demo_%E5%88%97%E8%A1%A8%E8%A7%86%E5%9B%BECCTableView
【3.x】
(1)去掉 "CC"
(2)TableViewCell 中:
> unsigned int getIdx() 返回类型改为 ssize_t(类型为 long)
(3)TableViewDataSource 中:
> unsigned int idx 类型改为 ssize_t(类型为 long)
(4)TableView 中:
(A)排列方向:setDirection()
> CCScrollViewDirection 改为强枚举 ScrollView::Direction
// HORIZONTAL //只能横向滚动 VERTICAL //只能纵向滚动。默认方式//
(B)排列方式:setVerticalFillOrder()
> CCTableViewVerticalFillOrder 改为强枚举 TableView::VerticalFillOrder
// TOP_DOWN //从小到大排列,即idx从小到大。0 1 2 3 BOTTOM_UP //从大到小排列,即idx从大到小。3 2 1 0。默认方式//
(5)其他变化不大。
【CCTableView】
CCTableView继承于CCScrollView,所以它具备了能够触摸滑动的功能,CCTabelView就像是一个大容器,内部由若干个CCTableViewCell单元项组成。
学习过CCScrollView之后,大家应该能够很好的理解CCTableView是如何操作的吧?实际上就是在CCScrollView的基础上,增加了对视图的容器container中的子节点对象的管理相关操作,即每个对象都是一个列表项CCTableViewCell。
如果还未学过滚动视图CCScrollView,直接看列表视图CCTableView可能会比较吃力,所以务必先掌握CCScrollView的用法。
在使用CCTableView的过程中会涉及到四个类。
(1)列表单元项 CCTableViewCell
(2)列表数据处理 CCTableViewDataSource
(3)列表事件委托代理 CCTableViewDelegate
(4)列表视图 CCTableView
1、CCTableViewCell
CCTableViewCell是CCTableView的单元项cell的数据类型,它继承于节点类CCNode,并且每一项cell都含有一个唯一的标识符,允许TableView通过不同的index来更新TableviewCell。
如果说视图的容器container是一个大容器的话,那么CCTableViewCell相当于是一个小容器。container放的都是每一项cell,而cell放的就是每一项的数据信息。什么CCLabel、CCSprite、CCMenu全都可以放在cell上面。
常用操作如下:
// class CCTableViewCell: public CCNode, public CCSortableObject { //设置cell的唯一标示符idx void setIdx(unsigned int uIdx); unsigned int getIdx(); };//
2、CCTableViewDataSource
CCTableViewDataSource是非常重要的一个类,CCTableView的数据相关的处理都与该类有关。
这个必须由CCTableView所在的CCLayer图层继承,并且必须要继承如下四个虚构函数。
以下四个虚构函数都是空实现,所以必须继承和实现相关代码。
其中:
(1)cellSizeForTable()为设置每项cell的尺寸大小,即每项的大小都一样。
(2)tableCellSizeForIndex()则是根据idx来设置尺寸大小,每项大小可以不一样。
这两个函数需要选择其中一个来继承和实现。
// class CCTableViewDataSource { //设置每项cell的尺寸大小 virtual CCSize cellSizeForTable(CCTableView *table); //根据idx来设置每项cell的尺寸大小 virtual CCSize tableCellSizeForIndex(CCTableView *table, unsigned int idx); //获取编号为idx的cell //若还未生成idx的cell,那么就创建该项cell的内容 virtual CCTableViewCell* tableCellAtIndex(CCTableView* table, unsigned int idx) = 0; //列表中一共多少项cell virtual unsigned int numberOfCellsInTableView(CCTableView *table) = 0; };//
3、CCTableViewDelegate
CCTableViewDelegate为列表视图的事件委托代理类,它继承于CCScrollViewDelegate。
这个也是必须由CCTableView所在的CCLayer图层继承,并且必须要继承如下三个虚构函数。
// class CCTableViewDelegate : public CCScrollViewDelegate { //当cell被点击时的回调函数,用于处理被触摸的cell数据 virtual void tableCellTouched(CCTableView* table, CCTableViewCell* cell) = 0; //继承于CCScrollView virtual void scrollViewDidScroll(cocos2d::extension::CCScrollView* view) {} //滚动时回调函数 virtual void scrollViewDidZoom(cocos2d::extension::CCScrollView* view) {} //放缩时回调函数 };//
4、CCTableView
CCTableView中的cell是可以重用的。比如我们需要在一个CCTableView中创建10个cell,而可视区域只能够显示5个cell。我们在对cell初始化的时候,只会创建5个cell对象,也就是只做了5次 cell = new CCTableviewCell(),这是因为在talbieview中存在一个重用队列,在开始的时候,这个重用队列中是没有任何东西的,每当你滑动tableview直到一个cell被滑到了不可见的区域,这个cell就会被加入到重用队列中,然后当有一个新的cell需要被显示出来时,我们就会使用table->dequeueCell()方法,在重用队列中获取一个cell,这样的话就避免了创建一个新的cell并为它开辟内存空间。
//class CCTableView : public CCScrollView, public CCScrollViewDelegate{/** * 2种创建 */ //dataSource:一般为this //size:列表视图的可视区域的尺寸大小 //container:自定义CCLayer容器。一般不推荐使用自定义容器 static CCTableView* create(CCTableViewDataSource* dataSource, CCSize size); static CCTableView* create(CCTableViewDataSource* dataSource, CCSize size, CCNode* container);/** * 常用函数 * setDirection , setVerticalFillOrder , * dequeueCell , cellAtIndex , * reloadData */ //设置列表项cell的排列方向 //CCScrollViewDirection: // kCCScrollViewDirectionHorizontal 横向排列 // kCCScrollViewDirectionVertical 纵向排列,默认方式 virtual void setDirection(CCScrollViewDirection eDirection); CCScrollViewDirection getDirection(); //设置列表项cell的排列顺序 //当列表视图纵向排列Vertical时有效,从上到下显示的cell的排列顺序 // kCCTableViewFillTopDown 从小到大排列,即idx从小到大。0 1 2 3 // kCCTableViewFillBottomUp 从大到小排列,即idx从大到小。3 2 1 0 void setVerticalFillOrder(CCTableViewVerticalFillOrder order); CCTableViewVerticalFillOrder getVerticalFillOrder(); //从重排队列中获得一个可用的cell //因为在我们滑动cell的时候有些cell是显示的,有些不是显示出来的,把没有渲染的cell拿过来 //这样就不用重新new出一个cell了,这样的话可以减小内存的开销 CCTableViewCell* dequeueCell(); //获得编号为idx的cell CCTableViewCell* cellAtIndex(unsigned int idx); //重新加载数据,当数据发生修改时调用 void reloadData();};//
5、关于排列方式
新创建的CCTableView默认的排列方式为:
(1)纵向排列: kCCScrollViewDirectionVertical
(2)按idx从大到小排列: kCCTableViewFillBottomUp
可以通过setDirection()设置排列方向,通过setVerticalFillOrder()设置排列顺序。
注意:若设置为横向排列,那么setVerticalFillOrder()就会失效了。
6、关于数据加载显示
当数据发生改变时,需要通过reloadData()重新加载数据。
否则显示的数据依旧还是未修改时的数据。
7、使用方法
(1)CCLayer继承两个相关类CCTableViewDataSource、CCTableViewDelegate。
(2)创建CCTableView,并设置可视区域大小。
(3)设置排列方向、排列顺序。
(4)设置委托代理setDelegate(this)。并实现两个继承类的相关函数。
【代码实战】
代码参考于cocos2dx的官方项目TestCpp。
1、资源图片
2、引入头文件和命名空间
// #include "cocos-ext.h" using namespace cocos2d::extension;//
3、继承CCTableViewDataSource、CCTableViewDelegate
并重写虚构函数及回调函数。
// class HelloWorld : public cocos2d::CCLayer,public CCTableViewDataSource, public CCTableViewDelegate { public: virtual bool init(); static cocos2d::CCScene* scene(); CREATE_FUNC(HelloWorld); //继承于CCTableViewDataSource virtual CCSize tableCellSizeForIndex(CCTableView* table, unsigned int idx); //根据idx来设置每项cell的尺寸大小 virtual CCTableViewCell* tableCellAtIndex(CCTableView* table, unsigned int idx); //获取编号为idx的cell virtual unsigned int numberOfCellsInTableView(CCTableView* table); //一共多少项cell //继承于CCTableViewDelegate virtual void tableCellTouched(CCTableView* table, CCTableViewCell* cell); //某项cell被点击时回调函数 virtual void scrollViewDidScroll(cocos2d::extension::CCScrollView* view); //滚动时回调函数 virtual void scrollViewDidZoom(cocos2d::extension::CCScrollView* view); //放缩时回调函数 };//
4、设置每个cell的大小
// //根据idx来设置每项cell的尺寸大小 CCSize HelloWorld::tableCellSizeForIndex(CCTableView* table, unsigned int idx) { if(idx == 2) return CCSizeMake(100,100); return CCSizeMake(60,60); }//
5、设置cell总项数
// //一共多少项cell unsigned int HelloWorld::numberOfCellsInTableView(CCTableView* table) { return 10; }//
6、设置每个cell的内容
在cell上添加一个精灵图片、一个Label标签。根据cell的编号idx,设置如上三类精灵图片。
// CCTableViewCell* HelloWorld::tableCellAtIndex(CCTableView* table, unsigned int idx) { char Icon[20]; //根据idx选中显示的图片 char number[10]; //显示label标签的数字 sprintf(Icon, "sp%d.png", idx%3 + 1); sprintf(number, "d", idx); //也可以用cell = table->cellAtIndex(idx); CCTableViewCell* cell = table->dequeueCell(); if(!cell) { cell = new CCTableViewCell(); cell->autorelease(); //自动释放资源 //添加一个精灵图片 CCSprite* sprite = CCSprite::create(Icon); sprite->setAnchorPoint(CCPointZero); sprite->setPosition(ccp(0, 0)); cell->addChild(sprite, 0, 1); //添加一个label标签 CCLabelTTF* label = CCLabelTTF::create(number, "Arial", 20); label->setPosition(CCPointZero); label->setAnchorPoint(CCPointZero); cell->addChild(label, 0, 2); } else { //更换精灵图片,使用纹理 CCTexture2D* texture = CCTextureCache::sharedTextureCache()->addImage(Icon); CCSprite* sprite = (CCSprite*)cell->getChildByTag(1); sprite->setTexture(texture); //更改图片编号 CCLabelTTF* label = (CCLabelTTF*)cell->getChildByTag(2); label->setString(number); } return cell; }//
7、触摸到某个cell的回调函数
// //某项cell被点击时回调函数 void HelloWorld::tableCellTouched(CCTableView* table, CCTableViewCell* cell) { CCLOG("cell touched at index: %i", cell->getIdx()); //控制台输出 }//
8、创建两个CCTableView
一个横向、一个纵向。并设置相关属性、及委托代理。
// CCSize mysize = CCDirector::sharedDirector()->getVisibleSize(); //横向CCTableView CCTableView* tableView1 = CCTableView::create(this, CCSizeMake(250, 60)); tableView1->setPosition(ccp(20, mysize.height/2 - 30)); this->addChild(tableView1); //属性设置 tableView1->setBounceable(false); //关闭弹性效果 tableView1->setDirection(kCCScrollViewDirectionHorizontal); //横向 tableView1->setDelegate(this); //委托代理 tableView1->reloadData(); //加载数据 //纵向CCTableView CCTableView* tableView2 = CCTableView::create(this, CCSizeMake(60, 250)); tableView2->setPosition(ccp(mysize.width - 150, mysize.height/2 - 120)); this->addChild(tableView2); //属性设置 tableView2->setDirection(kCCScrollViewDirectionVertical); //纵向 tableView2->setVerticalFillOrder(kCCTableViewFillTopDown); //从小到大排列 tableView2->setDelegate(this); //委托代理 tableView2->reloadData(); //加载数据//
9、运行结果
10、分析与总结
(1)注意CCTableView继承于CCScrollView,即也是继承于CCLayer,故它会忽略锚点的设置,其锚点始终为(0,0)。
(2)大家发现没有,左边那组关闭弹性效果后,触摸移动起来感觉很不爽呀。
(3)编号为02的旁边为何会有这么大的间隔呢?这是因为我在设置单元项cell大小的时候,故意设置了编号为02的大小为100*100,其他的均为60*60。
(4)还有一点,倘若你要修改某一项的数据时,修改完后,记得要重新加载数据reloadData()。