Greg Maletic
Greg Maletic

Reputation: 6337

iOS: Using UIAppearance to define custom UITableViewCell color

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?

Upvotes: 22

Views: 12643

Answers (4)

SmileBot
SmileBot

Reputation: 19642

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.

Upvotes: 3

lxt
lxt

Reputation: 31304

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!

Upvotes: 42

Senthil
Senthil

Reputation: 1

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!!!

Upvotes: 0

Nate Potter
Nate Potter

Reputation: 3222

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.

Upvotes: 17

Related Questions