191

I would like to customize the background (and maybe the border too) of all of the UITableViewCells within my UITableView. So far I have not been able to customize this stuff, so I have a bunch of white background cells which is the default.

Is there a way to do this with the iPhone SDK?

TheNeil
  • 3,321
  • 2
  • 27
  • 52
jpm
  • 16,622
  • 34
  • 63
  • 66

18 Answers18

206

Here is the most efficient way I have come across to solve this problem, use the willDisplayCell delegate method (this takes care of the white color for the text label background as well when using cell.textLabel.text and/or cell.detailTextLabel.text):

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { ... }

When this delegate method is called the color of the cell is controlled via the cell rather than the table view, as when you use:

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

So within the body of the cell delegate method add the following code to alternate colors of cells or just use the function call to make all the cells of the table the same color.

if (indexPath.row % 2)
{
    [cell setBackgroundColor:[UIColor colorWithRed:.8 green:.8 blue:1 alpha:1]];
}
else [cell setBackgroundColor:[UIColor clearColor]];

This solution worked well in my circumstance...

zoul
  • 102,279
  • 44
  • 260
  • 354
Nathan B.
  • 2,195
  • 2
  • 12
  • 6
  • This is a way cleaner solution. Most of the other solutions require either subclassing the UITableViewCell. vlado.grigorov's solution don't work for me. – Ronnie Liew Jan 24 '10 at 17:19
  • Indeed, and this is the method Apple themselves recommend according to various WWDC presentations I have seen. – Mike Weller Apr 06 '10 at 08:08
  • Nice - EXCEPT when you need to add new rows at top of the list. This method make all additions same color. Refresh does fix it, but takes unnecessary time. Found out yesterday... – JOM Apr 16 '10 at 04:13
  • This seems to work well, except when using Core Data. New cells added via an NSFetchedResultsController do not seem to call willDisplayCell properly. I am at a loss making it work... – radven Jun 11 '12 at 07:31
  • The equivalent line for setting background color in Swift 2.0: `cell.backgroundColor = UIColor.clearColor` – kbpontius Mar 02 '16 at 22:28
197

You need to set the backgroundColor of the cell's contentView to your color. If you use accessories (such as disclosure arrows, etc), they'll show up as white, so you may need to roll custom versions of those.

Ben Gottlieb
  • 85,404
  • 22
  • 176
  • 172
105

This is really simple, since OS 3.0 just set the background color of the cell in the willDisplayCell method. You must not set the color in the cellForRowAtIndexPath.

This works for both the plain and grouped style :

Code:

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
    cell.backgroundColor = [UIColor redColor];
}

P.S: Here the documentation extract for willDisplayCell :

"A table view sends this message to its delegate just before it uses cell to draw a row, thereby permitting the delegate to customize the cell object before it is displayed. This method gives the delegate a chance to override state-based properties set earlier by the table view, such as selection and background color. After the delegate returns, the table view sets only the alpha and frame properties, and then only when animating rows as they slide in or out."

I've found this information in this post from colionel. Thank him!

Seba
  • 1,051
  • 2
  • 9
  • 3
59

The best approach I've found so far is to set a background view of the cell and clear background of cell subviews. Of course, this looks nice on tables with indexed style only, no matter with or without accessories.

Here is a sample where cell's background is panted yellow:

UIView *backgroundView = [ [ [ UIView alloc ] initWithFrame:CGRectZero ] autorelease ];
backgroundView.backgroundColor = [ UIColor yellowColor ];
cell.backgroundView = backgroundView;
for ( UIView *view in cell.contentView.subviews ) 
{
    view.backgroundColor = [ UIColor clearColor ];
}
Alex Zavatone
  • 4,106
  • 36
  • 54
Vladimir Grigorov
  • 10,903
  • 8
  • 60
  • 70
19

Simply put this in you UITableView delegate class file (.m):

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell  forRowAtIndexPath:(NSIndexPath *)indexPath 
{
    UIColor *color = ((indexPath.row % 2) == 0) ? [UIColor colorWithRed:255.0/255 green:255.0/255 blue:145.0/255 alpha:1] : [UIColor clearColor];
    cell.backgroundColor = color;
}
GrandMasterFlush
  • 6,269
  • 19
  • 81
  • 104
JAG
  • 226
  • 2
  • 3
7

I concur with Seba, I tried to set my alternating row color in the rowForIndexPath delegate method but was getting inconsistent results between 3.2 and 4.2. The following worked great for me.

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {

    if ((indexPath.row % 2) == 1) {
        cell.backgroundColor = UIColorFromRGB(0xEDEDED);
        cell.textLabel.backgroundColor = UIColorFromRGB(0xEDEDED);
        cell.selectionStyle = UITableViewCellSelectionStyleGray;
    }
    else
    {
        cell.backgroundColor = [UIColor whiteColor];
        cell.selectionStyle = UITableViewCellSelectionStyleGray;
    }

}
cobbal
  • 69,903
  • 20
  • 143
  • 156
cipherz
  • 543
  • 6
  • 10
  • 1
    Still do not understand why setting it in willDisplayCell makes any difference. It's called anyway whether we implement that or not right? – user4234 Nov 29 '12 at 11:24
6

After trying out all different solutions, the following method is the most elegant one. Change the color in the following delegate method:

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (...){
        cell.backgroundColor = [UIColor blueColor];
    } else {
        cell.backgroundColor = [UIColor whiteColor];
    }
}
Jim Huang
  • 401
  • 5
  • 9
4

vlado.grigorov has some good advice - the best way is to create a backgroundView, and give that a colour, setting everything else to the clearColor. Also, I think that way is the only way to correctly clear the colour (try his sample - but set 'clearColor' instead of 'yellowColor'), which is what I was trying to do.

William Denniss
  • 16,089
  • 7
  • 81
  • 124
  • An advantage to this approach is that you can keep the color a design time property in Interface Builder. One less design issue that requires developer interaction. – whitneyland Aug 12 '11 at 23:34
  • 1
    cell.backgroundView = [[[UIView alloc] initWithFrame: cell.bounds ] autorelease]; cell.backgroundView.backgroundColor = [UIColor redColor]; – Brian Feb 17 '13 at 22:29
3

Create an image to use as background with Photoshop or gimp and name it myimage. Then, add this method to your tableViewController class:

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
    UIImage *cellImage = [UIImage imageNamed:@"myimage.png"];//myimage is a 20x50 px with  gradient  color created with gimp
    UIImageView *cellView = [[UIImageView alloc] initWithImage:cellImage];
    cellView.contentMode = UIContentViewModeScaleToFill;
    cell.backgroundView = cellView;
    //set the background label to clear
    cell.titleLabel.backgroundColor= [UIColor clearColor];
}

This will work also if you have set the UITableView to custom in attribute inspector.

Pang
  • 9,564
  • 146
  • 81
  • 122
Davide
  • 561
  • 4
  • 9
3

Customizing the background of a table view cell eventually becomes and "all or nothing" approach. It's very difficult to change the color or image used for the background of a content cell in a way that doesn't look strange.

The reason is that the cell actually spans the width of the view. The rounded corners are just part of its drawing style and the content view sits in this area.

If you change the color of the content cell you will end up with white bits visible at the corners. If you change the color of the entire cell, you will have a block of color spanning the width of the view.

You can definitely customize a cell, but it's not quite as easy as you may think at first.

Andrew Grant
  • 58,260
  • 22
  • 130
  • 143
  • 1
    This is definitely true for cells in Grouped tables, but Plain tables don't have as much to worry about. An unadorned cell with no accessories should look fine. – Ben Gottlieb Nov 11 '08 at 23:54
  • Ben - good point. I primarily use grouped tables but as you mention plain tables don't suffer from any of these problems. – Andrew Grant Nov 12 '08 at 18:45
3

Create a view and set this as background view of the cell

UIView *lab = [[UIView alloc] initWithFrame:cell.frame];
            [lab setBackgroundColor:[UIColor grayColor]];
            cell.backgroundView = lab;
            [lab release];
Senthil
  • 31
  • 2
3

To extend on N.Berendt's answer - If you want to set cell color based on some state in the actual cell data object, at the time you are configuring the rest of the information for the table cell, which is typically when you are in the cellForRowAtIndexPath method, you can do this by overriding the willDisplayCell method to set the cell background color from the content view background color - this gets around the issue of the disclosure button backgrounds etc. not being right but still lets you control color in the cellForRowAtIndexPath method where you are doing all of your other cell customisation.

So: If you add this method to your table view delegate:

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
    cell.backgroundColor = cell.contentView.backgroundColor;
}

Then in your cellForRowAtIndexPath method you can do:

if (myCellDataObject.hasSomeStateThatMeansItShouldShowAsBlue) {
    cell.contentView.backgroundColor = [UIColor blueColor];
}

This saves having to retrieve your data objects again in the willDisplayCell method and also saves having two places where you do tailoring/customisation of your table cell - all customisation can go in the cellForRowAtIndexPath method.

gamozzii
  • 3,911
  • 1
  • 30
  • 34
2

My solution is to add the following code to the cellForRowAtIndexPath event:

UIView *solidColor = [cell viewWithTag:100];
if (!solidColor) {

    solidColor = [[UIView alloc] initWithFrame:cell.bounds];
    solidColor.tag = 100; //Big tag to access the view afterwards
    [cell addSubview:solidColor];
    [cell sendSubviewToBack:solidColor];
    [solidColor release];
}
solidColor.backgroundColor = [UIColor colorWithRed:254.0/255.0
                                             green:233.0/255.0
                                              blue:233.0/255.0
                                             alpha:1.0];

Works under any circumstances, even with disclosure buttons, and is better for your logic to act on cells color state in cellForRowAtIndexPath than in cellWillShow event I think.

Pang
  • 9,564
  • 146
  • 81
  • 122
1

Subclass UITableViewCell and add this in the implementation:

-(void)layoutSubviews
{
    [super layoutSubviews];
    self.backgroundColor = [UIColor blueColor];
}
JonahGabriel
  • 3,066
  • 2
  • 18
  • 28
1
    UIView *bg = [[UIView alloc] initWithFrame:cell.frame];
    bg.backgroundColor = [UIColor colorWithRed:175.0/255.0 green:220.0/255.0 blue:186.0/255.0 alpha:1]; 
    cell.backgroundView = bg;
    [bg release];
Bhavesh Nayi
  • 3,626
  • 1
  • 27
  • 42
1

This will work in the latest Xcode.

-(UITableViewCell *) tableView: (UITableView *) tableView cellForRowAtIndexPath: (NSIndexPath *) indexPath {
    cell.backgroundColor = [UIColor grayColor];
}
Pang
  • 9,564
  • 146
  • 81
  • 122
Sameera R.
  • 4,384
  • 2
  • 36
  • 53
0

Try this:

- (void)tableView:(UITableView *)tableView1 willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    [cell setBackgroundColor:[UIColor clearColor]];
    tableView1.backgroundColor = [UIColor colorWithPatternImage: [UIImage imageNamed: @"Cream.jpg"]];
}
Pang
  • 9,564
  • 146
  • 81
  • 122
-1

If we can override your cell class, you can try this approach

override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
    super.init(style: style, reuseIdentifier: reuseIdentifier)
    selectionStyle = .none
}

override func setSelected(_ selected: Bool, animated: Bool) {
    super.setSelected(selected, animated: animated)
    backgroundColor = selected ? .red : .clear
}
Mark G
  • 124
  • 3
  • 5