Customizing the background/border colors of a UITableView (grouped style)

Customizing the background color of a UITableView is somewhat easy, but only if you use the plain style. If you use the grouped style of a table view, it starts to get way more complex. There are no easy ways to quickly set a property for the border color and the background color of the whole table view cell. Well, there are, but if you try to change some of these values and try to use the grouped style, it will look completely wrong.

Below you have a proper grouped table view using the standard Apple theme:

Standard style

Looks pretty good, and it is also very simple to build that in objective-c. Assuming you use Interface Builder for your UI work, just set the table view as a “grouped”, and then set the title property of each cell, like this:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"Cell";
 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
    }
    cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
 
    NSArray *list = [NSArray arrayWithObjects:@"First", @"Second", @"Third", nil];
    cell.text = [list objectAtIndex:indexPath.row];
 
    return cell;
}

So now let’s try something tricky and simply change the backgroundColor property of cell.contentView, as that works fine when dealing with “plain” style table views. The code would be just a bit different:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"Cell";
 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
    }
    cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
 
    NSArray *list = [NSArray arrayWithObjects:@"First", @"Second", @"Third", nil];
    cell.text = [list objectAtIndex:indexPath.row];
 
    cell.contentView.backgroundColor = [UIColor redColor];
 
    return cell;
}

And this is what it looks like:

Broken results

At first I thought about changing cell.backgroundView, but that doesn’t work. So you can see that changing the contentView doesn’t work either, and it actually breaks a bunch of things:

  • No rounded corners on the left side of the table view anymore
  • The background color on the disclosure image is still set to white
  • How do we change the border color anyway?

So after researching this problem for a while, and asking around for a solution, it seemed like there was no way to customize this stuff without a lot of manual work. Indeed that was the case, but Mike Akers (another StackOverflow.com member) posted the source code to a solution that he came up with, and that works very well so far. You can see his source code here for a custom background view with a border.

Here it is a modified version of my code to use his class:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"Cell";
 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
    }
    cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
 
    UILabel *label = [[[UILabel alloc] init] autorelease];
    label.font = [UIFont boldSystemFontOfSize:16.0f];
    label.frame = CGRectMake(40.0f, 10.0f, 220.0f, 22.0f);
    label.textColor = [UIColor whiteColor];
    label.backgroundColor = [UIColor clearColor];
    label.opaque = NO;
 
    NSArray *list = [NSArray arrayWithObjects:@"First", @"Second", @"Third", nil];
    label.text = [list objectAtIndex:indexPath.row];
    [cell.contentView addSubview:label];
 
    CustomCellBackgroundView *bgView = [[CustomCellBackgroundView alloc] initWithFrame:CGRectZero];
    if (indexPath.row == 0) {
        bgView.position = CustomCellBackgroundViewPositionTop;
    } else if (indexPath.row == 1) {
        bgView.position = CustomCellBackgroundViewPositionMiddle;
    } else {
        bgView.position = CustomCellBackgroundViewPositionBottom;
    }
    cell.backgroundView = bgView;
    cell.accessoryView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"more_arrow.png"]];
 
    return cell;
}

And the resulting interface:

Proper background and border colors

Ugly colors, but you get the idea. The code is also way more complex than before, but at least it’s possible to customize the background and border colors of a table view cell. This is more or less what we use on Knee Cap, our iPhone app that handles day to day money loans. This is what our custom table view looks like:

Knee Cap

32 Comments »

  1. MattjDrake said,

    February 26, 2009 @ 5:12 am

    Thanks for the post – this will come in handy. I made sure to write it up and link back to it in my blog:
    http://howtomakeiphoneapps.com/2009/02/customize-grouped-table-view-cells/

    Does anyone have any insight into using a custom image as a background in the grouped table?

  2. Adrian Kosmaczewski said,

    February 26, 2009 @ 6:18 am

    It seems that many of us had the same moment of happiness when Mike posted his solution in StackOverflow :) Actually a friend of mine here in Switzerland posted a code also based on Mike’s approach in Github:

    http://github.com/sburlot/tableviewcellwithbkgnd/tree/master

    Muito obrigado pela solução! :)

  3. jpm said,

    February 26, 2009 @ 10:02 am

    Adrian,

    Very cool, thanks for the pointer to the github project about this stuff.

    –Joao

  4. Mike said,

    February 26, 2009 @ 11:06 am

    I had a similar issue but decided on a very different approach. Rather than getting my main tableViewController code all full if switches and if/elses I just subclassed UITableViewController and made a method:

    - (UITableViewCell)getTableCellForIndexPath:(NSIndexPath*)indexPath andRowCount:(int)rowCount
    {}

    Then, getting a cell is MUCH cleaner:

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
    int rowCount = [self tableView:tableView numberOfRowsInSection:indexPath.section];
    UITableViewCell *cell = [self getTableCellForIndexPath:indexPath andRowCount:rowCount];

    // Do stuff
    }

  5. Steve said,

    February 26, 2009 @ 2:16 pm

    nice!
    i wonder how you replaced the blue-gray vertical stripes background with the much cooler greenish-striped horizontal background!!??
    /steve

  6. John said,

    February 26, 2009 @ 8:15 pm

    Nice, but in your modified example, I don’t see where you are setting the background color to red. How does this part work? Seems like you need to set the fillColor and borderColor properties of bgView…

  7. jpm said,

    February 26, 2009 @ 8:23 pm

    John,

    Correct, sorry about that. Since my own version of Mike Aker’s class only needs to use one set of background/border colors, I just set it manually within the class.

    Usually you would set the property manually after initializing the object. Something like this:

        CustomCellBackgroundView *bgView = [[CustomCellBackgroundView alloc] initWithFrame:CGRectZero];
        bgView.fillColor = [UIColor redColor];
        bgView.borderColor = [UIColor yellowColor];
        // ... rest of code

    Hope that helps!

    –Joao

  8. jpm said,

    February 26, 2009 @ 8:33 pm

    Steve,

    The way I did that was to create a UIImageView and put that as the background of my Nib view, then add the UITableView on top of it, and set the background color of the table view to [UIColor clearColor].

    –Joao

  9. Andy Peters said,

    February 28, 2009 @ 5:53 pm

    Nice write up! I like how you related it to Knee Cap too.

  10. Alainms23 said,

    March 7, 2009 @ 6:58 pm

    Very ! Very ! Very good work !
    Many Thanks !
    You can’t imagine how you saved my time ! ;-)

    Alainms23

  11. JohnW said,

    March 28, 2009 @ 3:13 pm

    Great work, many thanks!

  12. kaustubhv said,

    April 2, 2009 @ 3:10 pm

    Thanks a ton, the cell coloring stuff is damn useful.

  13. kaustubhv said,

    April 3, 2009 @ 4:05 pm

    hello. i was toying with my example app for a drill down table and I added an image view which did not work out, so i deleted the image view from IB. Unfortunately my previous table app is not working anymore. i cannot see the root level at all. Any clues what I need to do to restore bit back? is it some connections or something from the Inspector that need to be redone?

  14. iphone architect said,

    May 6, 2009 @ 1:51 am

    very nice tutorial, thanks

  15. Sun-ki Min said,

    May 20, 2009 @ 5:47 am

    thank you for your posting.
    it’s very nice code. i’ve already spent my time, but succes now. :)

  16. rahulvyas said,

    July 2, 2009 @ 8:35 am

    is there any way to do this without custom cell.means we can add label directly.without using custom cell

  17. Jiropole said,

    July 6, 2009 @ 2:57 pm

    Ditto on the thanks – this saved me a bunch of time as well. I tweaked the rounded-corner drawing code so it can draw single-pixel width cells centered on the pixel vs leaking over two pixels.

    One issue that’s come up for me is that when used with dequeueReusableCellWithIdentifier:, I may get a cell to which I’ve already added these custom subviews. I’m not sure how to strip these views back out or identify them, when a cell reuse occurs. As it is, these subviews build up and create a visual mess! I’m not too adept at using UIViews yet, does anyone know a simple way to find/remove these custom subviews in a cell reuse situation? Cheers!

  18. Jiropole said,

    July 6, 2009 @ 3:10 pm

    Apologies for the noise, but I figured out a way to clean up custom subviews using the UIView.tag property. No great revelation to you experienced programmers I’m sure :) I set the tag for any custom views to some arbitrary value, then every time I get a dequeued cell, I first remove any subviews having this tag.

  19. veddermatic said,

    July 16, 2009 @ 12:17 pm

    Thanks for the code, really helpful stuff. Quick question though… if i reload the table data, I get a second set of labels. What’s the best way to avoid that?

  20. Jay said,

    July 28, 2009 @ 6:42 am

    You can easily change the border colors of the uitableview by using this:

    [theTable setSeparatorColor:[UIColor blackColor]];

  21. Mark S said,

    August 5, 2009 @ 3:12 pm

    Thanks for the great method!
    As you do [[CustomCellBackgroundView alloc] initWithFrame:CGRectZero];
    Isn’t there a need for release somewhere?
    Or is it save to add to autorelease pool?
    Please correct if any of it true or false.

    Thanks again

  22. UITableView « Alexander Jäger said,

    October 22, 2009 @ 1:04 am

    [...] http://pessoal.org/blog/2009/02/25/customizing-the-background-border-colors-of-a-uitableview/ [...]

  23. yunas said,

    February 3, 2010 @ 7:36 am

    i want different separator color amongs the grouped cells …
    [theTable setSeparatorColor:[UIColor blackColor]]; is for a uniform difference amongst the cell separators but i want it to be random…
    plz ppl help….

  24. UACellBackgroundView at Under The Bridge said,

    May 19, 2010 @ 8:10 pm

    [...] nice, very nice. Based on this Stack Overflow question, which you can find more exposition on here; but hey, it only took us a few minutes to toss UACellBackgroundView into our current panic for a [...]

  25. Cameron Palmer said,

    June 3, 2010 @ 6:39 am

    That will work but violates the principle that there should be no transparency in UITableViewCells. It impacts scrolling smoothness negatively.

  26. Blake C said,

    June 14, 2010 @ 6:53 pm

    This code gives me errors in 3.0

  27. Rajiv said,

    July 29, 2010 @ 7:09 am

    One thing I have struggled with in the past is getting the UITableView to have a custom background when displaying in grouped mode. There is no option within Interface Builder (IB) to set this property on such a view, so you are always left with the standard blue background. However, it is possible to do this within the code of your application.

    I am going to use a view that will be a UIViewController that will adopt the UITableViewDelegate and UITableViewDatasource methods. First up create your view in the usual manner, add in the protocols and then add in the following attribute to the class:

    IBOutlet UITableView *myTableView;

    Obviously you can call your table view whatever you like. Now, in IB open up your NIB and navigate to the File’s Owner. If you are using the latest version of Xcode, you will probably already have this set to your class. If not set this now. In your view, add in a Table View from the library. Set the dataSource and delegate of this view in the connections pane of the Inspector to your File’s owner. Now, click on the File’s Owner icon and display its connections. Connect ‘myTableView’ to the table view you have added to your view. Save.

    At this point you can either add a UIImageView with an image and send this image to the back of the view hierarchy (under the Layout menu) or change the background colour of the view.

    From here, go to the source of your class and add the following into the

    - (void)viewDidLoad

    method:

    [myTableView setBackgroundColor:[UIColor clearColor]];

    When you display the view, your background image or colour should be visible under your grouped table.

  28. Niranjan said,

    August 11, 2010 @ 5:54 am

    Can you suggest any suggestion on
    “cell carry the bottom part of background image hence looks like background color broken and cell overlap on the screen”.
    Thanks

  29. Sijo said,

    December 2, 2010 @ 4:43 am

    Thanks for this post and github url of implementation..

  30. Drop shadow UITableView zoals clock.app - Pagina 3 - iPhone Forum - alles over de Apple iPhone, iPad en iPod touch said,

    February 25, 2011 @ 2:30 am

    [...] [...]

  31. shabbir ahmed said,

    May 7, 2011 @ 7:22 am

    how to use different color for each cell ?

  32. ???UITableView - ??? said,

    July 5, 2011 @ 1:27 am

    [...] Left: a default UITableView with three rows. Right: the same table view after customization. ?????????????http://pessoal.org/blog/2009/02/25/customizing-the-background-border-colors-of-a-uitableview/ [...]

RSS feed for comments on this post · TrackBack URI

Leave a Comment