Apr 28

Ohhk, quite a lot of things done but this one is something which I have used most often. Custom cells can sometimes greatly push ahead the usability of your application. In this post I am going to create a test project which will demonstrate how to create custom cells and use them appropriately to provide better usability. The application will finally look like this:

For basics and list of topics you can refer this post:

So to start open xcode and create a new project, chose the template as “Navigation Based” and name it as “CustomCellTestProject”. What template you chose does not matter, refer my previous posts to find how you can start working on any template.
First thing we will do is create a customCell. Right click on Classes and add a new UITableViewCell subclass. Name it as “CustomCell”. Now open CustomCell.h and add the following code:

#import

@interface CustomCell : UITableViewCell {

UILabel *primaryLabel;

UILabel *secondaryLabel;

UIImageView *myImageView;

}

@property(nonatomic,retain)UILabel *primaryLabel;

@property(nonatomic,retain)UILabel *secondaryLabel;

@property(nonatomic,retain)UIImageView *myImageView;

@end


Here we have simply added a primary label to display the primary text, a secondary label and an imageView. These elements will be created and added into the content view of our custom cell. So open CustomCell.m and add the following code

- (id)initWithFrame:(CGRect)frame reuseIdentifier:(NSString *)reuseIdentifier {

if (self = [super initWithFrame:frame reuseIdentifier:reuseIdentifier]) {

// Initialization code

primaryLabel = [[UILabel alloc]init];

primaryLabel.textAlignment = UITextAlignmentLeft;

primaryLabel.font = [UIFont systemFontOfSize:14];

secondaryLabel = [[UILabel alloc]init];

secondaryLabel.textAlignment = UITextAlignmentLeft;

secondaryLabel.font = [UIFont systemFontOfSize:8];

myImageView = [[UIImageView alloc]init];

[self.contentView addSubview:primaryLabel];

[self.contentView addSubview:secondaryLabel];

[self.contentView addSubview:myImageView];

}

return self;

}


We create the three elements and added them to the contentView of our cell. Also don’t forget to synthesize all the three elements as we are going to access these elements from other classes.

@synthesize primaryLabel,secondaryLabel,myImageView;

Now, we have already added the UI elements into our cell but you must have noticed, we have not yet defined how these elements will appear inside cell. Go ahead and add the following code for that:

- (void)layoutSubviews {

[super layoutSubviews];

CGRect contentRect = self.contentView.bounds;

CGFloat boundsX = contentRect.origin.x;

CGRect frame;

frame= CGRectMake(boundsX+10 ,0, 50, 50);

myImageView.frame = frame;

frame= CGRectMake(boundsX+70 ,5, 200, 25);

primaryLabel.frame = frame;

frame= CGRectMake(boundsX+70 ,30, 100, 15);

secondaryLabel.frame = frame;

}


You can do anything in this method to define the lay out of cell. I have simply assigned frames to all the elements.
You can also find a method in CustomCell.m

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {

[super setSelected:selected animated:animated];

// Configure the view for the selected state

}

This method can be used to define how your cell should react when it is selected. You can describe what should be the highlight color or may be you want to flash one of the labels anything of your choice. I am leaving this method as it is.
We are done with creating our custom cell and now we have to use it. Open RootViewController.m and import CustomCell.h at the top.


#import “CustomCell.h”

I am going to create 5 cells here, you can just use your own logic of specifying number of cells and data. So change the following method to look like this:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

return 5;

}

Now we are going to use our custom cell. If you look at the cellForRow method, you will find that a UItableViewCell has been created and re used. Now all we have to do is to replace this cell with our new cell. Change the code inside this method to look like this:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

static NSString *CellIdentifier = @”Cell”;

CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

if (cell == nil) {

cell = [[[CustomCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];

}

// Set up the cell…

switch (indexPath.row) {

case 0:

cell.primaryLabel.text = @”Meeting on iPhone Development”;

cell.secondaryLabel.text = @”Sat 10:30″;

cell.myImageView.image = [UIImage imageNamed:@"meeting_color.png"];

break;

case 1:

cell.primaryLabel.text = @”Call With Client”;

cell.secondaryLabel.text = @”Planned”;

cell.myImageView.image = [UIImage imageNamed:@"call_color.png"];

break;

case 2:

cell.primaryLabel.text = @”Appointment with Joey”;

cell.secondaryLabel.text = @”2 Hours”;

cell.myImageView.image = [UIImage imageNamed:@"calendar_color.png"];

break;

case 3:

cell.primaryLabel.text = @”Call With Client”;

cell.secondaryLabel.text = @”Planned”;

cell.myImageView.image = [UIImage imageNamed:@"call_color.png"];

break;

case 4:

cell.primaryLabel.text = @”Appointment with Joey”;

cell.secondaryLabel.text = @”2 Hours”;

cell.myImageView.image = [UIImage imageNamed:@"calendar_color.png"];

break;

default:

break;

}

return cell;

}


I have added some dummy data. You can use your data source to provide data for primaryLabel and secondaryLabel. Please note that I have used three images here. You can use any image of your choice. All you need to to do is copy the images and paste it into your project root folder (which in this case is CustomCellTestProject folder). After pasting the files, in xcode right click on Resources (or any group), select Add >> ExistingFiles and then select all the images you want to add in you project. Once added you can simply use them by their names.
Thats it, go ahead and run the project. You will find something wrong when you compare you simulator screen with mine. If you noticed in the CustomCell.m, I have given some frames to the UI elements. You need to make sure that the height of your cell large enough to accomodate all the elements. So add this following code and you fixed the issue:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

{

return 50;

}

Let me know if I have been missing something here.

37 Responses to “iPhone Tutorial: Creating a custom Table View Cell”

  1. rahulvyas says:

    awesome post ..

    it helps me alot..

    program works fine but it gives a warning

    initialization from distinct objective-c type

  2. ABC says:

    I have always tolerated some harmless warnings :P but can u tell me where exactly u found this warning, m kinda away from my work station

  3. Ak says:

    I got the “initialization from distinct objective-c type” warning as well, what was causing it?

  4. Ak says:

    OK, figured it out. I had to cast the new cell because the id don’t match…

    CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    Found the reference to is here: http://blog.andrewpaulsimmons.com/2008/07/warning-initialization-from-distinct.html

  5. BN says:

    This approach works excellent but if you choose for a grouped UITableView, does that change things in terms of positioning of the labels and imageViews? I have the impression that I can’t position all subviews as precisely as I can in, for example, interface builder.

    Any comments?

  6. ABC says:

    Hello bare_nature,
    No I don think not using grouped UITableView would affect the positioning of any sybViews.

    Regarding IB and this approach, precision wise it shouldn make difference but yest with IB you can do d same thing faster.
    I m used to writing graphics like this bt the main reason behind this approach is that it gives me a lot of control and I can re-use the same code over and over again with little modifications. If we used xib(s) then re-using or re-customization ultimately takes more time.
    Correct me if I am wrong, I am looking for some serius motivation 2 use IB

  7. Ram says:

    Its Really Great Dude
    For a new bee like me it works out great. I was working out with the same kind of app and fortunately i got in to ur blog and done with the work.
    Now i would like to display the zoomed image in the detailed view when i tap on the disclosure indicator.
    if possible please post the code for me naa.

  8. Jag says:

    Simple, very clear and very helpful. Thanks for the post

  9. ABC says:

    Hi Ram, sorry for the late reply. I can not write d code here coz m currently bzzy with other obligations but I can give suggestions.
    As such I don understand what u wnat to do, but if you jus want to zoom on image den u can create a UIImageView of larger frame and put the same image in.

  10. livecity says:

    I have alreay built an app with a tableview, but would love to use this as the opener for the app. My rootviewcontroller already has all the code for the existing tableview. Is there a way to do this?

    Thanks in advance,
    D

  11. livecity says:

    OK, I’ve done this tutorial 7 times now and all I get is a black screen. What gives?

  12. livecity says:

    Figured out my issue with the blank screen. Still wondering if I can incorporate it into my existing project and another big QUESTION: How would I have the fields filled from a .plist?

  13. Paul says:

    Is there a download link for the complete Xcode project somewhere? I can’t seem to find it on the page. Great topic by the way.

    Thanks!

  14. iphoneguy says:

    Hi,
    How do I change the default height of the table cell? I tried increasing the heights of myImageView.frame and primaryLabel.frame but the text got clipped.

  15. mark says:

    where is the code and images for this article please.
    thanks for good starting point

  16. dennis says:

    Great example. Thanks!

  17. ABC says:

    Hi liveCity,
    Just create a custom cell like that say MyCustomCell and replace it with UITableViewCell in the rootViewController…let me know if there are any issues..and btw sorry for the late reply.

  18. ABC says:

    Hi,
    First: sorry for the late reply.
    Second: I will put all my working code on rapidshare and provide a link soon. Just need a day or two.

  19. spirit says:

    Hi, i did it all like you say but when i try in iphone simularot it cannot run,always a suddenly error,with another of your appilcations it happens too.but i good tutorial but i want to run it

  20. Brian says:

    Do you have source code for this?

  21. Steve says:

    CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    error: ‘CustomCell’ undeclared (first use in this function)
    error: ‘cell’ undeclared (first use in this function)

    Any clue why I’d be getting these errors?
    Thanks.

  22. ABC says:

    You are getting this error prolly coz u did not make any CustomCell.m and CustomCell.h?

  23. Steve says:

    Hi ABC,

    Nope, I have created the full CustomCell.m and .h files.

  24. Sam says:

    Hi,
    My table cells have fixed height until selected. On selection I want to increase the hight of the selected cell. I have tried something but the selected cell is overlapping the next cell.

    Please let me know how will i resize the table so that there are no overlapping cells

    Thanks
    Sam

  25. Marco says:

    First of all great tutorial. It helped me to clarify some questions. However, when I try to adapt the cell class to use a UITextField for some cells in addition to the existing UILabel on other cells, things get a little nasty. Mainly the problem has to do with:
CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
If the cell is getting reused, because of a scrolling on the table view, a cell with a label control might be reused by dequeueReusableCellWithIdentifier when in fact the indexPath.row is for a row which needs a UITextField. I have a workaround now, but I believe it leads to memory leak issues. Any ideas ??


  26. What about orientation changes? Doesn’t handle them well, does it?

  27. dan says:

    GFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
    {
    return 50;
    }
    when i use this i got an error saying “pointer value used where a floating value expected..any suggestions?
    thanks

  28. Jes says:

    My cell is blank…Why???…

  29. Steve says:

    Im getting a warning – > warning: incompatible Objective-C types initializing ’struct UITableViewCell *’, expected ’struct CustomCell *’

    And that is regarding the following code.

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *CellIdentifier = @”Cell”;

    CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil)
    {
    cell = [[[CustomCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
    }

    Any advice would make a sad man happy again. Thank you!

  30. Adam says:

    To fix the warning, replace

    CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    with

    CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    That will fix the problem,

    Ad

  31. Ralf Bernert says:

    Steve,

    an explicit cast for *cell is required, just put a (CustomCell *) before the assignment:

    CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    Should work now without any warnings.

  32. Stan says:

    Steve

    Try this
    CustomCell *cell =(CustomCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

  33. Rahul says:

    Hi Great tutorial with nice explanations.I have a query here, Can i have a customized screen with labels,table view and other desired control but with a precondition that i get a navigation Controller through out the application? My requirement is to be easily able to toggle between view.If I choose a view based application as template then i guess i will have to maintain my own stack for multiple view,which is provided by default by navigation controller.Can u suggest me something. ***I liked your approach to design all controls melodramatically***. I will be waiting for your reply . thanks and Cheers

  34. Ravi says:

    Great !!!!!!!

    Really it helped me a lot. Thank you very much……

  35. Hugo Haas says:

    Hi,

    I want to put a UITextField into a UITableViewCell. I did, but now a can’t edit the content of the UITextField. Is possible put the UITextField and edit the content of this by user?

  36. Nobuo Miwa says:

    Hi, Thank you for great post !
    It works fine but I’ve got a warning as followings..

    ‘initWithFrame:reuseIdentifier:’ is deprecated (declared at /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator3.2.sdk/System/Library/Frameworks/UIKit.framework/Headers/UITableViewCell.h:188)
    at
    if (self = [super initWithFrame:frame reuseIdentifier:reuseIdentifier]) {

    I’m using in Split View-Based Application.
    Could you please give some advice ?

Leave a Reply

preload preload preload