I have a table cell being displayed that shows a users image, name and some text. The user's image is 50x50, but I want a border around it so I set the view to center the image and set the frame to 52x52 and then set the background color of that view to my border color. That shows a 1 pixel border around the image.
I also want to show a 30 pixel wide border on the right of the cell when the cell is selected. I've tried to do that by creating a UIView the size of the cell's frame, then adding a subview to that view with a UIView the width and background color I would like. I then set that view to the selectedBackgroundView of the cell.
The problem here is that the cell's selectedBackgroundView gets applied to the background of all views inside the cell. So when I select a cell, the images "border" gets set to the cell's selected background color, the other 30px "border" I'm adding gets changed to that background color also.
Code inside my cellForRowAtIndexPath:
cell = (UserCellView *) currentObject;
UIView *c = [[UIView alloc ] initWithFrame:CGRectMake(0, 0, 30, cell.frame.size.height)];
c.backgroundColor = [[UIColor alloc] initWithRed:64/255.0 green:64/255.0 blue:64/255.0 alpha:1.0];
UIView *v = [[UIView alloc ] initWithFrame:cell.frame];
v.backgroundColor = [[UIColor alloc] initWithRed:35/255.0 green:35/255.0 blue:35/255.0 alpha:1.0];
[v addSubview:c];
cell.selectedBackgroundView = v;
[c release];
[v release];
I'll assume that you haven't actually tested what's going on to form your analysis that it "gets applied to the background of all views inside the cell".
I did something like this:
@interface TestView : UIView {
}
@end
@implementation TestView
-(void)setBackgroundColor:(UIColor*)c {
// Breakpoint here.
NSLog("setBackgroundColor: %@",c);
[super setBackgroundColor:c];
}
@end
...
UIView * v = [[[UIView alloc] initWithFrame:(CGRect){{0,0},{20,20}}] autorelease];
v.backgroundColor = [UIColor magentaColor];
UIView * v2 = [[[TestView alloc] initWithFrame:(CGRect){{5,5},{10,10}}] autorelease];
v2.backgroundColor = [UIColor yellowColor];
[v addSubview:v2];
cell.selectedBackgroundView = v;
The end result is that -setBackgroundColor:
is called from -[UITableViewCell _setOpaque:forSubview:]
when the view is selected, with something like UIDeviceWhiteColorSpace 0 0
(i.e. [UIColor clearColor]
).
Or, in other words, the background colour of some of the subviews are set to [UIColor clearColor]
while the cell is selected, allowing selectedBackgroundView to show through. I think this happens because a common optimization is to give textLabel
/detailTextLabel
the table's background colour (e.g. white) so it draws faster, but this means the background colour has to be reset when the cell is selected.
The easiest fix is to use an image instead: a 1-by-1-pixel image of the correct colour in a UIImageView will work, if a bit messy. (I had this problem when drawing custom separator lines with 1-pixel-high UIViews, so I just included the separator into the background image.)
An alternative fix is to use a CALayer instead: Add a 52x52 sublayer to the UIImageView's layer, and set the sublayer's background colour. I'm pretty sure UITableViewCell simply walks the view hierarchy, so it should ignore custom layers. (The big disadvantage with layers is that they don't auto-size, which made them unsuitable for my purposes, and means the 30px right border won't auto-size.)
A workaround is to subclass the relevant views and ignore -setBackgroundColor:
if it's equal to [UIColor clearColor]
.
A simple but obnoxious-to-maintain solution is to override setSelected:animated: and setHighlighted:animated: with implementations re-setting the various backgrounds you want. Something along the lines of:
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
self.childView.backgroundColor = [UIColor blueColor]; // whichever you want
}
First add this to your file
#import <QuartzCore/QuartzCore.h>
Then turn your view into an image with...
UIView *rowView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 1.0, 60.0)];
rowView.backgroundColor = [UIColor colorWithRed:35/255.0 green:35/255.0 blue:35/255.0 alpha:1.0];
UIGraphicsBeginImageContext(rowView.bounds.size);
[rowView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *yourImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Then instead of adding a UIView to your cell, just add a UIImageView with "yourImage".
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With