iOS: Using UIAppearance to define custom UITableViewCell color
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!
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.
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.