Article contributed by saim80
Introduction to CCTableViewSuite
Table view is an essential part of UIKit. Most app uses it to show data because of its efficient memory management and attractive scrolling experience. Even, in game development, table view is often required, i.e., device list for network play, list of settings/options, and level boards. To meet such requirements, developers either need to write their own table implementation or need to use UITableView. Using UITableView often causes extra efforts to create separate classes and code, mixing it with Cocos2d code. In addition, it cannot take advantage of any Cocos2d features because it is not a subclass of
CCNode. Due to this motivation, I decided to port my table view implementation that was based on UIKit a while ago. As it is the first draft for Cocos2d, I decided to port only the essential part that closely assimilates UITableView’s behavior.In the following sections, I will discuss features and limitations of
CCTableView and how to use it.You can download this project from:
- Download CCTable.zip (it is different from what was posted in the forum.)
Features and Limitations of CCTableView Classes
CCTableViewSuite consists of three classes:
CCScrollView, CCTableView, and CCMultiColumnTableView.CCScrollView is a subclass of CCLayer and super class of all table classes. It performs the following tasks:- Content clipping
- Auto-scrolling by flick-and-release
- Bouncing
- Three scroll direction types: vertical, horizontal, and both
- Generating scroll event messages via delegate
CCScrollView is very similar to UIKit’s UIScrollView but it does not provide zooming and scroll lock. CCScrollView requires you to modify CCNode’s visit method. Please read ‘How To’ section for the details.You must not add another
CCScrollView as its content if you enabled boundary clipping. CCScrollView uses OpenGL clipping planes, from plane0 to plane3, to cut its visible bounds. OpenGL provides a finite number of clipping planes while CCNode allows infinite number of CCNode objects to be added as its descendants regardless of the depth.The current implementation supports only cpp(0.0f, 0.0f) as anchor points for the table itself and its content. For the content, It is automatically set when one of
addChild: methods are called.CCTableView is a subclass of CCScrollView. It uses datasource and delegate protocols to do the following tasks:- Cell layout
- Memory management for cells by enqueueing the hidden cells that are completely clipped by visible bounds, dequeueing cells.
- Uses
CCNodeobjects as data. So any cocos2d object can be used. You can take full advantage manipulating the table itself or its cells by Cocos2d library. - Touch detection for cells.
Due to the fact that
CCTableView uses the left, bottom corner of the screen as its origin, it will fill cells from the left, bottom corner to the right, top corner.Cell size won’t be detected automatically, and all cells must have the equal size. You need to override
CCTableViewCell class to provide cell size. It is very possible to detect cell size and let them be different for a table. However, it requires for the table object to iterate all cells to compute its content size. Hence, it is not supported.CCMultiColumnTableView is a subclass of CCTableView. It simply does one more thing, allowing cells to be aligned in multiple columns.How To Use CCTableViewSuite
All classes’ interfaces are very similar to what you can find in UIKit and Cocos2d. However, You need to modify CCNode as the following or refer to the CCNode.m included in the download.
Modifying CCNode
This modification allows CCScrollView to clip its content. beforeDraw and afterDraw are overriden by CCScrollView class.
In CCNode.m,
-(void) beforeDraw {} -(void) draw {} -(void) afterDraw {} -(void) visit { if (!visible_) return; glPushMatrix(); if ( grid_ && grid_.active) { [grid_ beforeDraw]; [self transformAncestors]; } [self transform]; [self beforeDraw]; for (CCNode * child in children_) { if ( child.zOrder = 0 ) [child visit]; } [self afterDraw]; if ( grid_ && grid_.active) [grid_ afterDraw:self]; glPopMatrix(); } |
Creating CCScrollView
// size defines the scroll view’s visible bounds CCScrollView *view = [CCScrollView scrollViewWithViewSize:size]; CCSprite *sprite = [CCSprite spriteWithFile”img.png”]; //setting positions, CCLayer’s anchorPoint is ccp(0.0f, 0.0f), screen origin. sprite.position = ccp(0.0f, 0.0f); view.position = ccp(0.0f, 0.0f); view.contentOffset = ccp(0.0f, 0.0f); // setting internal content container (CCLayer) position. view.contentSize = sprite.contentSize; [view addChild:sprite]; [self addChild:view]; |
You may want to modify properties, depending on your needs.
CCScrollView Properties
delegategenerates DidScroll event. Table views will update its content during this event.isDraggingreadonly.YES, if users is touching the view.bouncesSet it toYESto let scroll view to stop scrolling at the edges of its content. NO will let users to scroll its content up to predefined insets.directionScrolling direction:CCScrollViewDirectionVertical,CCScrollViewDirectionHorizontal, orCCScrollViewDirectionBoth.clipToBoundsSet it toNOwill disable clipping. The content that exceeds the visible bounds will still be visible.contentOffsetThe location ofCCLayerobject which acts as a container for the content. You can scroll programmatically by using this property orsetContentOffset:animated:method.viewSizedetermines visible bounds.isEnabledenables/disables user interactions.
Defining Cell Size
@interface MyCell : CCTableViewCell {} @end @implementation MyCell +(CGSize)cellSize { return CGSizeMake(?,?); }@end |
Creating CCTableView
CCTableView *myTable = [[CCTableView tableViewWithDataSource:self size:size]; myTable.position = ccp(0.0f, 0.0f); myTable.tDelegate = [delegate]; //set if you need touch detection on cells. [self addChild:table]; [table reloadData]; |
Implementing Delegates
@interface TableViewScene : CCLayer # CCTableViewDelegate, CCTableViewDataSource # { @private CCTableView *myTable; } +(id)scene; @end @inplementation TableViewScene //provide data to your table //telling cell size to the table -(Class)cellClassForTable:(CCTableView *)table { return [MyCell Class]; } //providing CCNode object for a cell at a given index -(CCTableViewCell *)table:(CCTableView *)table cellAtIndex:(NSUInteger)idx { CCTableViewCell *cell CCSprite *sprite; cell = [table dequeueCell]; sprite = //create a proper sprite for the index, idx. if (!cell) { //there is no recycled cells in the table cell = [[MyCell new] autorelease]; // create a new one } //configure the sprite.. do all kinds of super cool things you can do with cocos2d. cell.node = sprite; return cell; } -(NSUInteger)numberOfCellsInTableView:(CCTableView *)table { //return a number } //touch detection here -(void)table:(CCTableView *)table cellTouched:(CCTableViewCell *)cell { //check if table is the one you expected. // if so, do something useful if (table == myTable && cell.idx == 0) { [cell.node runAction:cachedAction]; } } @end |
CCMultiColumnTableView
Do exactly what you would do for
CCTableView. It will automatically adjust cell layout, depending on cell size and the table’s viewSize property. To control the number of columns manually, set colCount to a number you want and direction to CCScrollViewDirectionBoth.






Very cool stuff, I was looking for something like this
. I only wish you would use the same method names in your delegate as the names in the UITableViewDelegate etc. You seem to be doing the same things, so why not make it easy for everyone with UIKit experience to integrate this? Since the only documentation on how to use it is this blog post.
Thanks. Yup, that seems reasonable, but I chose different names because it actually acts semantically different from what UITableView does for now.
Wow… very cool. Seems like the Pro end of the community is really raising the bar and contributing some seriously nice extensions to Cocos2d. Very much appreciate the effort and organization that when into this project.
Brendang
I would just like to point out a little typo in your post when overriding CCNode (the visit method):
for (CCNode * child in children_) {
if ( child.zOrder = 0 )
[child visit];
}
the equal sign should be ‘<'.
I noticed this because instead of importing your modified CCNode.m I decided to use Objective-C categories. It makes things a lot easier for when you want to update to a newer cocos2d version so you won't have to re-modify cocos2d.
If anyone is interested in using this technique, just create an empty .m file (call it whatever) and paste this in.
#import "cocos2d.h"
@implementation CCNode (CCTableViewSuite)
-(void) beforeDraw
{
// override me
// Only use this function to draw your staff.
// DON'T draw your stuff outside this method
}
-(void) draw
{
// override me
// Only use this function to draw your staff.
// DON'T draw your stuff outside this method
}
-(void) afterDraw
{
// override me
// Only use this function to draw your staff.
// DON'T draw your stuff outside this method
}
-(void) visit
{
if (!visible_)
return;
glPushMatrix();
if ( grid_ && grid_.active) {
[grid_ beforeDraw];
[self transformAncestors];
}
[self transform];
[self beforeDraw];
for (CCNode * child in children_) {
if ( child.zOrder = 0 )
[child visit];
}
[self afterDraw];
if ( grid_ && grid_.active)
[grid_ afterDraw:self];
glPopMatrix();
}
@end
Saim, thanks for sharing this great code… anyway, when I try to implemented the code… I got an error in the CCScrollView.m
//CCAssert(NO, @”CCScrollView: DO NOT initialize CCScrollview directly.”); //
it said implicit delacration of function CCAssert… but if I comment it, it works just fine, but still i feel something is wrong…
Anyone had the same problem and solution? sorry for my noob question…
thanks in advance….
I’ve been working on a project now and i am experiencing a problem in releasing the cctableview. it keeps on overlapping the existing table whenever i go to the other table then go back to the previous scene that has a CCTable. they keep on overlapping the existing tables and it gives me a pain in the ass solving this problem.The table is kinda laggy when i keeps on doing that. please help me on how to properly release the CCTable.
I also had problems releasing the CCTableView. It turned out to be that the table never got unregistered from the touch dispatcher (and thereby the dispatcher was retaining it). I suggest commenting out the line “[[CCTouchDispatcher sharedDispatcher] addStandardDelegate:self priority:0];” in “-(id)initWithViewSize:(CGSize)size” for CCScrollView. And then you instead use [table setIsTouchEnabled:] when creating the table. Hope that helps.
Little bug in CCScrollView: Cells are sometimes not displayed when scrolling animated (with large tables) via setContentOffset.
Fix:
-(void)stoppedAnimatedScroll:(CCNode *)node {
[self unschedule:@selector(performedAnimatedScroll:)];
[delegate_ scrollViewDidScroll:self];
}
stefanm
July 7, 2010 at 2:24 pm
i have it bug too, the message come to table in another screen when table is release!!!
stefanm
Thank you , its really work
I am experiencing a bug now… when i use [CCDirector sharedDirection]replaceScene] to Run the table
it works at the first time, but crashed the while app when the second time I call replaceScene…
I’ve tried in the example and it crashed too …
add a bug report on github.
A patch posted from someone.
http://twinsgames.tumblr.com/post/1357375617/patch-for-cctableview
I posted it only because i found it, i haven’t tried the bug (and then the patch). But if someone can, please fix it on this site.
Hello,
I’m a newby in programming on iPhone.
I just want to create a tableview in cocos2d and change the background of the touched cell.
Can you give me a hint?
Hi!
I found the same bug as Yop described.
There is 2 way to fix it.
First, simple but not cool- you need to call
[[CCTouchDispatcher sharedDispatcher] removeDelegate: MyTable];
in your dealloc method. In this way some one who read your code missunderstand why you do this…
Second is addition to first – you to remove call
[[CCTouchDispatcher sharedDispatcher] addStandardDelegate:self priority:0];
in CCScrollView.m :
-(id)initWithViewSize:(CGSize)size {
if ((self = [super init])) {
self.container_ = [CCLayer node];
self.viewSize = size;
isEnabled = YES;
delegate_ = nil;
bounces_ = YES;
clipToBounds_ = YES;
container_.contentSize = CGSizeZero;
direction_ = CCScrollViewDirectionBoth;
container_.position = ccp(0.0f, 0.0f);
[self addChild:container_];
// [[CCTouchDispatcher sharedDispatcher] addStandardDelegate:self priority:0]; this you shoild commit!
}
return self;
}
and now in your scene you will call this method instead in of CCScrollView
vTable = [CCTableView tableViewWithDataSource:self size:CGSizeMake(width, height)];
[[CCTouchDispatcher sharedDispatcher] addStandardDelegate:self priority:0];
Thats it!
First way you always need to do, and second is addition that makes code clear
Responde to Yod
first way:
CCScrollView.m
//add code
-(void)dealloc
{
[[CCTouchDispatcher sharedDispatcher] removeDelegate: self];
[super dealloc];
}
second way:
CCScrollView.m
-(id)initWithViewSize:(CGSize)size
{
if ((self = [super init]))
{
self.isTouchEnabled = YES; //add
………
//[[CCTouchDispatcher sharedDispatcher] addStandardDelegate:self priority:0];
}
}
@Saim80: this was a great help.
For my particular use I needed to have tables that were closer to a UIKit sectioned table. As a result I added the ability to have sections and section headers. If anyone is interested I will post.
@Bird,
No problem. I don’t think you need to ask about uploading your implementation. People will definitely appreciate your work if you do so.
Thanks.
Another solution for the CCTouchDispatcher problem that everyone is talking about is in the scroll view to comment out the offending line and overide registerWithTouchDispatcher in CCLayer as follows
- (void)registerWithTouchDispatcher
{
[[CCTouchDispatcher sharedDispatcher] addStandardDelegate:self priority:0];
}
Then CCLayer will take care of removing the added delegate. Other solutions may in fact be adding the delegate twice, didn’t checkup on that though.
@saim80, I’ll clean it up and post soon.
Works well with images. Has anyone used it with text, say, like multiple lines of text. An implementation like Facebook that uses combo text and images would be nice.
When I do a multiple line CCLabel it goes haywire (meaning the the scrolling doesn’t work. Touching the screen makes it jump all over). If anyone has an example on how to use this with multiple lines of text it would be appreciated, I didn’t see one in the CCTable project.
Hey, the link seems to be down. Could you maybe fix it?
Thx!
Done. Thanks.
However, the archive just updated doesn’t have sample projects nor re-factored for ‘CC’ prefix. The additional features and changes made were described at the forum, http://www.cocos2d-iphone.org/forum/topic/6821.
The zip file included is not the one being described in this article and as far as I have tested it is not working on Cocos2D 2.0.
Is this project dead? Any hopes of porting it to cocos2d 2.0? I would be happy to sponsor some development if someone can get it working to our specifications.
I have some issues with this. The download (zip file) gives SWTableView not CCTableView. If I try to change the code posted above to SWTableView the code no longer works, certain methods do not exist such as initing the table is different in SWTableView than the code above.
Frankly there needs to be a real solution for integrating tableviews that is supported by cocos2d and put in the extensions.
if you copy & paste the code replace
& with &
and
if ( child.zOrder = 0 ) with if ( child.zOrder == 0 )
oops
& amp; with &
Is there an update to this?
Does anybody know what happened to this? I just downloaded the tableView zip which has SWTableView and others. I am unable to follow the implementation of it.
I have this so far:
CGSize size = CGSizeMake(320,480);
SWTableView *myTable = [SWTableView viewWithDataSource:self size:size];
//SWTableView *myTable = [[SWTableView tableViewWithDataSource:self size:size];
myTable.position = ccp(0.0f, 0.0f);
myTable.delegate = self; //set if you need touch detection on cells.
[self addChild:myTable];
[myTable reloadData];
Inside my CCLayer (which is in my CCScene). I get lexical processor errors on SWDebug and I also get XCode trying to change CCArray to NSArray.
Is there an update to this? I don’t think it will work for cocos2d 2.0…
To all of you requesting a version compliant with cocos2d 2.0:
I spent some time scratching my head over this, but I think it works now. I put the code on my site for now and might upload it to github at a later time. I also added the proof-of-concept example classes to the zip. Please note, that anything else than anchorPoint(0,0) still does not work. Maybe someone else can change this. I added the boundingBox method to SWScrollView, which is the starting point when adding anchorPoint flexibility.
You can find the code here.
I tested on iOS 6.1.3, iPhone 3 GS, iPhone 4, iPad 3 and iPad 2 in order to cover both retina and non-retina for the two device families.