22

If I set the backgroundColor attribute on a grouped UITableViewCell, the background color successfully changes. Great.

But I'd like to use UIAppearance to change the background color on all my UITableViewCells, so I can do it in one place and affect a change everywhere. Here's my code:

[[UITableViewCell appearance] setBackgroundColor:[UIColor colorWithRed:30.0/255.0 green:30.0/255.0 blue:30.0/255.0 alpha:1.0]];

UITableViewCell implements UIAppearance and UIAppearanceContainer, so I would have thought this would work. But it doesn't. I've also tried using -[UITableViewCell appearanceWhenContainedIn:(Class)], and that doesn't work either.

Any ideas?

Greg Maletic
  • 6,225
  • 8
  • 54
  • 73

4 Answers4

42

Update (2013/7/8) - This has been fixed in newer versions of iOS. However, it's worth knowing about if you're targeting iOS 6 or below.

You can blame Apple for this one, and it's actually pretty mean of them. Technically, backgroundColor is not customizable through appearance proxies.

From Apple's documentation:

To support appearance customization, a class must conform to the UIAppearanceContainer protocol and relevant accessor methods must be marked with UI_APPEARANCE_SELECTOR.

If we go into a class like UIBarButtonItem and look at the tintColor property we see this:

@property(nonatomic,retain) UIColor *tintColor UI_APPEARANCE_SELECTOR;

So because it's marked with the UI_APPEARANCE_SELECTOR tag we know it works with UIAppearance.

Here's where Apple are particularly mean: in a UIView, backgroundColor has no appearance selector tag, but still works with UIAppearance. According to all the documentation Apple provide it should not, but yet it does!

This gives the misleading impression that it will work for all sub-classes of UIView, including UITableView. This has come up before, in this previous SO answer

So the bottom line is that backgroundColor shouldn't work at all with UIAppearance, but for some reason it does on a UIView. It is not guaranteed to work on UIView subclasses, and it doesn't work at all on UITableView. Sorry I couldn't give you a more positive answer!

Community
  • 1
  • 1
lxt
  • 31,146
  • 5
  • 78
  • 83
  • Thanks for the explanation. I would probably have spent a few hours nodding my head against the wall because of this. – matsr Nov 29 '11 at 21:06
  • If this is something that really bothers you (it bothers me!), definitely file a bug report with Apple. I don't think it's really a 'bug' per se, but it's definitely a deficiency. I think I may even have seen someone from Apple use `setBackgroundColor` in a code demo once on appearance proxies. – lxt Nov 30 '11 at 11:17
  • @lxt: I am looking at iOS 7 and don't see that it was fixed. Can you please send me an email (my email in address) to discuss. I understand that iOS 7 is still under NDA, so you don't want to put here information, until it's available. – Victor Ronin Aug 12 '13 at 23:27
  • @VictorRonin - are you looking at the `UITableViewCell` header file? – lxt Aug 13 '13 at 09:28
  • @lxt: Yes. And there is only thing which is marked by UI_APPEARANCE_SELECTOR (it's not a background). – Victor Ronin Aug 13 '13 at 14:37
  • You can add add UI_APPEARANCE_SELECTOR using a category, but don't. Mysterious things will happen, since UITableviewCells are used on controls that might surprise you, like pickers! Been there done that. – SmileBot Dec 17 '14 at 19:23
17

You can create your own subclass of UITableViewCell that conforms to UIAppearance and mark a custom setter with UI_APPEARANCE_SELECTOR. Then set the cell backgroundColor on the superlass from your custom setter .

In your appDelegate

[[CustomCell appearance] setBackgroundCellColor:[UIColor redColor]];

In your UItableView subclass

@interface CustomCell : UITableViewCell <UIAppearance>

@property (nonatomic, weak) UIColor *backgroundCellColor UI_APPEARANCE_SELECTOR;

@implementation CustomCell

@synthesize backgroundCellColor;

-(void)setBackgroundCellColor:(UIColor *)backgroundColor
{
    [super setBackgroundColor:backgroundColor];
}

I'm using ARC in this example.

Nate Potter
  • 3,222
  • 2
  • 22
  • 24
  • Even without subclassing, you can use a category and custom properties to proxy appearance calls. It can be useful if you want to theme a part where you can't use a subclass (like for the `UIPrintInteractionController` for example). – Tom Dec 23 '13 at 18:38
3

Without Subclassing! Doing this on a subclass is probably NOT the best practice, especially if you want to hit all tableView backgrounds. That's a lot of subclassing. A lot of potential bugs. A mess really. The best way to do this is to use a category. You will have to set one up for both the tableViewCell and the tableView. I will just demonstrate the one for the cell. The property on the tableView you must do is the backgroundColor property. NB. I'm prepending my methods with "sat".

// .h

    #import <UIKit/UIKit.h>

@interface UITableViewCell (Appearance)<UIAppearance>
@property (strong, nonatomic) UIColor *satBackgroundColor UI_APPEARANCE_SELECTOR;
@end

// .m

#import "UITableViewCell+Appearance.h"

@implementation UITableViewCell (Appearance)

- (UIColor *)satBackgroundColor
{
    return self.backgroundColor;
}

- (void)setSatBackgroundColor:(UIColor *)satBackgroundColor
{
    self.backgroundColor = satBackgroundColor;
}


@end

Now in your appDelegate or some manager class you'll import the category and just call it as if it had an appearance proxy built in.

UITableViewCell *cell = [UITableViewCell appearance];
cell.satBackgroundColor = [UIColor orangeColor];

Ok, so now just do the one for the tableView's background property. Simple.

SmileBot
  • 19,393
  • 7
  • 65
  • 62
0

I used category for this. Below is the sample code In your .h file write

*@interface UITableViewCell (MyCustomCell)
@property (nonatomic, weak) UIColor *backgroundCellColor UI_APPEARANCE_SELECTOR;
@end*

In your .m file write

*@dynamic backgroundCellColor;
-(void)setBackgroundCellColor:(UIColor *)backgroundColor
{
    [super setBackgroundColor:backgroundColor];
}*

It worked well for me. :) Thanks Nate!!!

Senthil
  • 1
  • 1
  • 3