Sometimes you may want to have a different background color on your table views than Apple White. One problem you will most likely be facing is that this makes it impossible to use the regular table view cell accessories. Black arrows on black background are kinda hard to see.
You will have to draw your own. And in this post I’m going to show you how I did it.

Just today I discovered a mechanism that makes it even easier to roll your own custom-colored accessory view. The property name containing the word “view” is somewhat misleading in this case. You might be tempted to create your own UIView subclass and override the drawRect to draw there. This has one disadvantage though, you cannot switch colors when the cell gets highlighted.
UIView does not possess the properties selected , enabled and highlighted. For these you have to turn to UIControl which does. And I discovered by trying it out that if you don’t use a UIView for your custom-colored accessory, but UIControl instead, then these properties get happily triggered by the table view itself. All you have to do is choose the correct drawing color based on the current state.
Here is my implementation of a disclosure indicator that can have any color for the regular and the highlighted state.
DTCustomColoredAccessory.h
@interface DTCustomColoredAccessory : UIControl { UIColor *_accessoryColor; UIColor *_highlightedColor; } @property (nonatomic, retain) UIColor *accessoryColor; @property (nonatomic, retain) UIColor *highlightedColor; + (DTCustomColoredAccessory *)accessoryWithColor:(UIColor *)color; @end |
DTCustomColoredAccessory.m
#import "DTCustomColoredAccessory.h" @implementation DTCustomColoredAccessory - (id)initWithFrame:(CGRect)frame { if ((self = [super initWithFrame:frame])) { self.backgroundColor = [UIColor clearColor]; } return self; } - (void)dealloc { [_accessoryColor release]; [_highlightedColor release]; [super dealloc]; } + (DTCustomColoredAccessory *)accessoryWithColor:(UIColor *)color { DTCustomColoredAccessory *ret = [[[DTCustomColoredAccessory alloc] initWithFrame:CGRectMake(0, 0, 11.0, 15.0)] autorelease]; ret.accessoryColor = color; return ret; } - (void)drawRect:(CGRect)rect { // (x,y) is the tip of the arrow CGFloat x = CGRectGetMaxX(self.bounds)-3.0;; CGFloat y = CGRectGetMidY(self.bounds); const CGFloat R = 4.5; CGContextRef ctxt = UIGraphicsGetCurrentContext(); CGContextMoveToPoint(ctxt, x-R, y-R); CGContextAddLineToPoint(ctxt, x, y); CGContextAddLineToPoint(ctxt, x-R, y+R); CGContextSetLineCap(ctxt, kCGLineCapSquare); CGContextSetLineJoin(ctxt, kCGLineJoinMiter); CGContextSetLineWidth(ctxt, 3); if (self.highlighted) { [self.highlightedColor setStroke]; } else { [self.accessoryColor setStroke]; } CGContextStrokePath(ctxt); } - (void)setHighlighted:(BOOL)highlighted { [super setHighlighted:highlighted]; [self setNeedsDisplay]; } - (UIColor *)accessoryColor { if (!_accessoryColor) { return [UIColor blackColor]; } return _accessoryColor; } - (UIColor *)highlightedColor { if (!_highlightedColor) { return [UIColor whiteColor]; } return _highlightedColor; } @synthesize accessoryColor = _accessoryColor; @synthesize highlightedColor = _highlightedColor; @end |
To use this in a tableview cell, all you need to do is this:
// in cellForRowAtIndexPath: DTCustomColoredAccessory *accessory = [DTCustomColoredAccessory accessoryWithColor:cell.textLabel.textColor]; accessory.highlightedColor = [UIColor blackColor]; cell.accessoryView =accessory; |
After discovering the thing about UIControl and highlighted, I modified it to also take a highlight color. Having this handy saved me quite some time today when I implemented a white-on-black look for a mock up app I’ve been contracted to produce.
Categories: Recipes
Hi, came across your post & wanted to say thanks. One thing, I am wondering how one might mimic
- (void)tableView: (UITableView *)tableView accessoryButtonTappedForRowWithIndexPath: (NSIndexPath *)indexPath
given that it appears this method is not called when using either an accessory view or your custom accessory.
well, then you have to have touch handling on your own accessory. If it’s a button, then addTarget:selector:
thank you very much
Awesome thanks for this!
nice addition – thanks. I tweaked a little so that it can do checkmarks too. Just add a BOOL property for check:
+ (CustomColouredDisclosure *)accessoryWithColor:(UIColor *)color
{
CustomColouredDisclosure *ret = [[[CustomColouredDisclosure alloc] initWithFrame:CGRectMake(0, 0, 15.0, 15.0)] autorelease];
ret.accessoryColor = color;
return ret;
}
- (void)drawChevron:(CGRect)rect
{
// (x,y) is the tip of the arrow
CGFloat x = CGRectGetMaxX(self.bounds)-5.0;
CGFloat y = CGRectGetMidY(self.bounds);
const CGFloat R = 4.5;
CGContextRef ctxt = UIGraphicsGetCurrentContext();
CGContextMoveToPoint(ctxt, x-R, y-R);
CGContextAddLineToPoint(ctxt, x, y);
CGContextAddLineToPoint(ctxt, x-R, y+R);
CGContextSetLineCap(ctxt, kCGLineCapSquare);
CGContextSetLineJoin(ctxt, kCGLineJoinMiter);
CGContextSetLineWidth(ctxt, 3);
if (self.highlighted)
{
[self.highlightedColor setStroke];
}
else
{
[self.accessoryColor setStroke];
}
CGContextStrokePath(ctxt);
}
- (void)drawCheck:(CGRect)rect
{
// (x,y) is the tip of the arrow
CGFloat x = CGRectGetMaxX(self.bounds)-3.0;;
CGFloat y = 3;
const CGFloat R = 3.5;
CGContextRef ctxt = UIGraphicsGetCurrentContext();
CGContextMoveToPoint(ctxt, x, y);
CGContextAddLineToPoint(ctxt, x-1.8*R, y+3*R);
CGContextAddLineToPoint(ctxt, x-2.7*R, y+2*R);
CGContextSetLineCap(ctxt, kCGLineCapRound);
CGContextSetLineJoin(ctxt, kCGLineJoinRound);
CGContextSetLineWidth(ctxt, 3);
if (self.highlighted)
{
[self.highlightedColor setStroke];
}
else
{
[self.accessoryColor setStroke];
}
CGContextStrokePath(ctxt);
}
- (void)drawRect:(CGRect)rect
{
if (self.check)
{
[self drawCheck:rect];
}
else
{
[self drawChevron:rect];
}
}
Thanks a lot for this.
Thanks. Works great.
[...] let me also give you the custom accessory view, which is based on my previous article on how to custom-draw a disclosure indicator I simply added a type enum and modifications in [...]