Custom Cells

Custom cells are an extremely useful UI element to use in apps that I have been using since the start of iOS development and I wrote a tutorial (below) to show hoe to create custom cells in IB. Since then, there has been a lot of development around frameworks and libraries for custom cells. I’ve recently written a review on Sensible Cocoa’s Sensible TableView which might be of interest to readers.

Creating the project

Create a new project with the “View-based Application” template and call it customTableCell.

Setting up the view controller

Open customTableCellViewController.h and add two IB outlets which we will use to reference to the custom UITableViewCell objects which we will create later. Also, we are going to be using this as a table view delegate and data source so we should state that this class will conform to these protocols. Your customTableCellViewController.h should look like this after editing:

#import <UIKit/UIKit.h>

@interface customTableCellViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>  {
	IBOutlet UITableViewCell *cellOne;
	IBOutlet UITableViewCell *cellTwo;
}

@property (nonatomic, retain) IBOutlet UITableViewCell *cellOne;
@property (nonatomic, retain) IBOutlet UITableViewCell *cellTwo;

@end

Adding the items in Interface Builder

Open customTableCellViewController.xib and drop in a Table View (not a Table View Controller), making it fill the view.

Set the the table view properties to Style -> Grouped.

Link the delegate and dataSource outlets of the table view to “File’s Owner” as illustrated by this screenshot:

ib-tableview-links.png

Add two Table View Cell items in IB to your customTableCellViewController.xib file. Then, open each table view cell item and drop something different onto each one of them so you will tell them apart.

Now we need to link these table view cells to the IB outlets we created earlier. To do this, right click on “File’s Owner” and link cellOne and cellTwo outlets to the table view cells you have just created. You should then have something which looks like this:

ib-cell-links.png

Save and close customTableCellViewController.xib.

Controller Code

Open customTableViewController.m

We will need to implement three functions, namely tableView:cellForRowAtIndexPath:, numberOfSectionsInTableView: and tableView:numberOfRowsInSection: which are the usual data source protocol functions which we need to implement. The three functions are shown below.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
	if([indexPath row] == 0) return cellOne;
	if([indexPath row] == 1) return cellTwo;
	return nil;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
	return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
	return 2;
}

These functions tell the table view to display 1 section, with 2 cells and when the table view asks for each cell, the custom UITableViewCell objects are returned.

And that’s it!

If you now build and run the application then you will notice that your custom cells are being shown – brilliant! Now you can do something fun with the custom cells! For instance you could put a text box or a slider in it and then bind actions of it to a function in your view controller to act upon the user’s input.

Go play!

EDIT: – Updated for Xcode 4

39 Responses to “Custom UITableViewCell in IB”

  1. Emil says:

    Great tutorial! First one that I’ve seen that actually shows how to add custom table cells using IB and not entirely programmatically. Keep up the good work.

  2. Thank you for your kind words Emil! I’ll certainly try to keep releasing tutorials – I’ve been doing them when I come across something which I’ve found hard to find information about on the internet / books.

    Interestingly, the UITableViewCell thing has been approached by so many people in so many different ways, and there’s no true right or wrong way really.

    Anyway, glad you liked the tutorial!

  3. David says:

    This can’t be right. ???
    tableView:cellForRowAtIndexPath: returns a new UITableViewCell for each row. In your tutorial, it is returning the same object repeatedly!

    For example, consider the conventional code:

    if ((cell = [tableView dequeueReusableCellWithIdentifier:item_type]) == nil) {
    cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:item_type] autorelease]; …

    So, shouldn’t it be something like:

    if ((cell = [tableView dequeueReusableCellWithIdentifier:item_type]) == nil) {
    cell = [[cellOne copy] autorelease];…

    ?

  4. Hi David,

    What you say is sort of true, but in my example, there are only ever 2 rows. Therefore cellForRowAtIndexPath is returning a certain cell for row 0 (1st row) and a certain cell for row 1 (2nd row). This enables me to create the cell in IB and link it with outlets like I have shown.

    Your method would be a good addition to be able to do the case where you have a generic cell which you want to use more than once in the same table, but want to use IB to create the cell and have it in the same XIB as the rest of the interface.

    Matt

  5. bare_nature says:

    Hello,

    Great tutorial Matt! A quick question: If you want to make your cells higher than the standard cells, how do you make sure that they are working properly? What I mean is that when making your custom cells higher, they are cut off sort of as they don’t fit in a standard cell (if this is clear at all).

    Keep up the great work!

    BN

  6. Hello!

    Yes you can do that with the heightForRowAtIndexpath function. Take a look at the documentation for the table view data source protocol and you should be able to find that function. You can just return a different height for each of your cells. Then you can make those cells the correct height in IB and you’re away. If you set things correctly in IB with regard to auto-resizing options then you’d even be able to have variable sized cells if you wanted.

    Hope that helps!

  7. HenrikB says:

    I started writing a tutorial about this a few days ago and finished it a few minutes ago, so if you want to see an alternative way of doing this check out my blog and feel free to comment!

    http://humblecoder.blogspot.com/2009/05/iphone-tutorial-creating-table-cells-in.html

    It’s not as professional looking as Matt’s, but hopefully as informative.

  8. Nice little tutorial there Henrik! I like the idea you’ve done there, slightly different way of doing it to me. I’ve actually developed another method for doing custom cells as well but I really hope Apple decide to make it easier somehow because the difficulty is that you can’t have a NIB which is purely a view, which is just annoying…

  9. dinesh says:

    Good Tutorial…I want to have a two cell in a row,as in contacts we have “text message” and “add to favourites” in a single row how to do that…. can anyone help me?

  10. Carol says:

    > Also, we are going to be using this as a table view delegate and
    > data source so we should state that this class will conform to these
    > protocols

    You *SHOULD*… but you didn’t.

  11. Kathy says:

    > Add two Table View Cell items in IB to your
    > customTableCellViewController.xib file.

    Where do you drop them in? Into the rows in the tableView?

    > Then, open each table view cell item and drop something

    How do you “open” a cell up?

  12. Jill says:

    *PLEASE* alway show a screen-shot of the final, completed screen.

    Just “wishing” that your screen looks like my screen… is useless.

  13. > You *SHOULD*… but you didn’t.
    Apologies, that was WordPress taking away the < , > thinking that it was an HTML tag. Rectified now.

    > Where do you drop them in? Into the rows in the tableView?
    You drop them into the XIB itself at the same level as the main UIView in there, as per the 2nd screenshot.

    > How do you “open” a cell up?
    Double click on it.

    > *PLEASE* alway show a screen-shot of the final, completed screen.
    > Just “wishing” that your screen looks like my screen… is useless.
    Good idea.

    This was just a very quick tutorial – it’s not part of the remit of this site that I provide “good” tutorials, I just try to help out others with what I’ve found out myself. Apologies if the tutorial wasn’t to the standard you’d hoped.

  14. Ian says:

    I think you should add the case where you are creating more than two as this is a typical requirement of cell subclassing

  15. Rene Pardon says:

    Hi,

    this is a very simple to understand tutorial. It was really helpful.
    Thank you for that :)

    regards
    René

  16. OE says:

    Amazing! After 5 hours of searching, a simple tutorial for custom cells in IB! Thanks!

  17. Nick says:

    This is a very simple and easy tutorial but for some reason my UITableViewCell objects are always nil so the program crashes. It appears as if interface builder is not linking them to the IBOutlets. Although, if I click the file’s owner in interface builder it shows all cells are properly linked.

    Any suggestions?

  18. Karib says:

    Thanks for this great tutorial. It saves me time on the table view that I would like to create.
    For table view with 2 sections with 1 row on each section, the following codes can be used.

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *tvcSection = nil;
    int iSection = (int)[indexPath section];
    switch (iSection) {
    case 0: tvcSection = cellOne;
    break;
    case 1: tvcSection = cellTwo;
    break;
    }
    return tvcSection;
    }

    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 2;
    }

    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 1;
    }

  19. Sascha says:

    Hi Matt,

    awesome! Thx for the straightforward tutorial, it saved me a lot of time.

    I came across one problem: In my app, I need to dynamically show and hide 5 cells I created as exposed. That’s no problem using the “hidden” property of the cells, however, I need this behaviour animated. So what I’ve tried to do first of all instead of hiding is deleting the cells like this:

    [fooTable deleteRowsAtIndexPaths:[NSArray arrayWithObject:fooIndexPath]] withRowAnimation:UITableViewRowAnimationTop];

    This results in the following exception:

    ‘Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (3) must be equal to the number of rows contained in that section before the update (5), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted).’

    I’m not sure if this has something to do with the dataSource which should probably be updated as well, but… how?

    Thanks for any suggestions!

    cheers,
    Sascha

  20. Brad Goodman says:

    Nick:

    I believe you are having your problem because you are deriving your subclass from “UITableViewController” – which would make sense – but in reality, you need to derive it from “UIViewController” (and then add delegates for UITableViewDataSource and UITableViewDelegate) – just as he did in this example.

    I was having the same issue – after changing just the declaration in the header file as such – no more nil cells.

  21. Blake says:

    Brad Goodman, you are amazing, you just saved me SO much trouble trying to figure out why this damn thing wouldn’t work. I owe you one. And for you Matt, great job at helping me out with this. I just got started in iPad development and this article helped a great bit. Thanks for the awesome tutorial.

  22. calebhc says:

    Thanks a lot for this tutorial. It was really helpful! Thanks! :)

  23. phaljica says:

    “The number of rows contained in an existing section after
    the update (3) must be equal to the number of rows contained in
    that section before the update (5), plus or minus the number of
    rows inserted or deleted from that section (0 inserted, 1
    deleted).” You can out more?

  24. Chip says:

    Wow, Matt. Clean. Concise. Accurate. And THE most helpful tutorial I have ever found on this subject. In fact, after two days of frustration, I had almost given up. But decided on one more click in my Google list and, man, am I glad I did! Thank you, thank you, thank you!

  25. Rui says:

    Hey there, is a way to reuse the cells? I am having problems to reuse, because the specific cell is inside the ViewController’s xib, instead of having her own xib.

  26. @Rui – This concept is specifically for single cells, so reuse makes no sense – they are only used in one place. So this is for if you have a username cell and a password cell – you return the username cell for cell 0 and the password cell for cell 1.

    If you want to create a generic cell that you can allocate as many times as you want, then you’ll need to subclass UITableViewCell yourself. Then you can make use of UITableView’s cell reuse.

  27. Rui says:

    Thanks Matt, got it working. :D

  28. Sha says:

    Hello

    Great tutorial, well written and simple.

    I am running into some problems.. form IB i have created an Img and UILable on the content view of the Cellone. When running in simulator i can see both image and lable . When published in device i am only able to see Image.I dont know where i went wrong. Pls help

  29. RAfiq says:

    Hi Matt,

    Am doing an app and have struck at a point based on sqlite database.
    At first I have to create two tables on same view.In that tables I have to insert values from sqlite database tables.
    In first table i have to get the values from first table.And in second table i have to get the values from second table by comparing with the foreign key.

    table1 table2

    id name id id2 name1
    1 Mohammed 1 1 ABC

    2 Rafiq 2 1 DEF

    3 2 ghi

    in first table i need values Mohammed,Rafiq.

    And when i click on Mohammed i used to get ABC,DEF in second table or if select Rafiq then ghi must display.
    and the selected data must be displayed in text fields.

    Thank u

  30. Nekbeth says:

    Hi, Great Tutorial. Simple and effective, just the way I like it. I was wondering if any of you guys know how to Set up the cell in order to show an image on different cells (like this tutorial) but not in the same row because I’ll be pushing that cell to another tableview and I don’t want the old image.

    This works for this tutorial and to show just different views in the same table:

    // Set up the cell…
    if (indexPath.row == 0) return cellOne;

    if (indexPath.row == 1) return cellTwo;

    Now, my data comes from a .plist, so I’m thinking to call the Value Name of the Title by doing the following:

    NSDictionary *dictionary = [self.tableDataSource objectAtIndex:indexPath.row];
    cell.textLabel.text = [dictionary objectForKey:@"Title"];

    now.. if anybody can help me to call that specific Title in order to return a particular cell .. it would awesome. Thanks

  31. [...] I want to create custom UiTableViewCell, and it works, when I create TableView, like in this example, by inherit from UIViewController. But when I create controller which inherit from [...]

  32. caul58 says:

    What about the case you want to reuse cellOne for 3 times for example in the same tableview?

  33. @caul58 – That’s not possible with this style of doing custom cells unfortunately. You could create a copy of the cell in viewDidLoad though and then use that for the other cell. Although I usually just create a copy in the NIB as I never find I need exactly the same cell – I usually use this method for different form elements such as username & password.

  34. caul58 says:

    Thanks. I will create a cellTVFactory and i will get the elements of every cell by their tag. It’s the best solution for me. Thanks again for solve my question.

  35. Hi,

    It is a good tut. But it’s not in xcode4.. Here is another tutorial in xcode4 http://www.altinkonline.nl/tutorials/xcode/uitableview/uitableviewcell/

  36. Cullen says:

    This is great tutorial. Simple but powerful technique. Thanks.

Leave a Reply