UITableViewCell makes label's background clear when highlighted
Asked Answered
G

10

42

I have a UIlabel on a UITableViewCell, which I've created programmatically (i.e. not a nib or a subclass).

When the cell is highlighted (goes blue) it makes all the background colors of the UILabels turn clear. I have 2 UILabels where I don't want this to be the case. Currently I'm using UIImageViews behind the UILabel's to make it look like the background color doesn't change. But this seems an inefficient way to do it.

How can i stop certain UILabel's background color changing when the UITableViewCell is highlighted?

Grinnell answered 3/6, 2010 at 10:33 Comment(0)
G
0

I had to subclass the UItableView, create a list of tags of the view that I want to not make transparent background, and override the setHighlighted:animated: method so that it reset the specific labels background colour. longwinding and fidely, if only I had the source code t the UItableViewCell's actual class.

Grinnell answered 3/6, 2010 at 14:4 Comment(0)
I
55

You need to subclass UITableViewCell and override the following two methods:

Objective-C:

- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated
{
    UIColor *backgroundColor = self.myLabel.backgroundColor;
    [super setHighlighted:highlighted animated:animated];
    self.myLabel.backgroundColor = backgroundColor;
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
    UIColor *backgroundColor = self.myLabel.backgroundColor;
    [super setSelected:selected animated:animated];
    self.myLabel.backgroundColor = backgroundColor;
}

Swift

override func setSelected(_ selected: Bool, animated: Bool) {
    let color = myLabel.backgroundColor
    super.setSelected(selected, animated: animated)
    myLabel.backgroundColor = color
}

override func setHighlighted(_ highlighted: Bool, animated: Bool) {
    let color = myLabel.backgroundColor
    super.setHighlighted(highlighted, animated: animated)
    myLabel.backgroundColor = color
}
Instruct answered 2/3, 2014 at 14:36 Comment(2)
Works perfectly for my custom button, thank you! However, this issue feels like an oversight on Apple's part...Thanks for the solution though ;)Klein
This worked for me, but i also had to add set the color in the "setSelected"Rumney
B
47

Another way to keep the background color from changing on highlight is to set the backgroundColor property on the label's layer instead of on the label itself.

#import <QuartzCore/QuartzCore.h>

...

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    // Get a table cell
    UITableViewCell *cell = [tableView dequeueReusableCellForIdentifier:@"cell"];

    // Set up the table cell
    cell.textLabel.text = @"This is a table cell.";

    // If you're targeting iOS 6, set the label's background color to clear
    // This must be done BEFORE changing the layer's backgroundColor
    cell.textLabel.backgroundColor = [UIColor clearColor];

    // Set layer background color
    cell.textLabel.layer.backgroundColor = [UIColor blueColor].CGColor;

    return cell;
}

The layer is not affected by cell highlighting or selection.

Bowen answered 18/2, 2014 at 21:45 Comment(8)
This is a great idea, but it doesn't seem to work on iOS 6. For iOS 7 and up, this should be the preferred method. Keep in mind that layer.backgroundColor is a CGColor, so you will need cell.textLabel.layer.backgroundColor = [[UIColor blueColor] CGColor];Dishcloth
@ColinTremblay: Good catch on the CGColor, thanks. I had no idea this didn't work in iOS 6... in playing around in the iOS 6.1 simulator it seems to work if you first set the UILabel's backgroundColor property to [UIColor clearColor]. Weird. I've updated the answer to reflect both fixes.Bowen
Great find. This is by far the easiest and best solution.Dishcloth
Wow!!.That was awesome. Setting textLabel background to clearColor and then setting required color to textLabel's layer did the work. :) Thank you so much @BowenGrunberg
works great for labels. In Swift 3 it would be cell.numberLabel.backgroundColor = UIColor.clear cell.numberLabel.layer.backgroundColor = UIColor.white.cgColor I couldn't get it to work in the same way for UIImageView, though- any ideas?Masquer
this should be the top solutionCassowary
Could only get this to work after removing the hard coded color from the storyboard, so if you're using a storyboard, make sure to NOT set the background color in the label there.Cipango
This solution has worked for me in the past (on a textView or label I believe), but did NOT work on my custom button on iOS 10.2Klein
B
41

Alternatively subclass the label you don't want to change color:

@interface PersistentBackgroundLabel : UILabel {
}

- (void)setPersistentBackgroundColor:(UIColor*)color;

@end


@implementation PersistentBackgroundLabel

- (void)setPersistentBackgroundColor:(UIColor*)color {
    super.backgroundColor = color;
}

- (void)setBackgroundColor:(UIColor *)color {
    // do nothing - background color never changes
}

@end

Then set the color once explicitly using setPersistentBackgroundColor:. This will prevent background color changes from anywhere without using your custom explicit background color change method.

This has the advantage of also eliminating clear background in label during transitions.

Belton answered 18/10, 2010 at 21:49 Comment(3)
I never thought of that, it's a good idea. At the moment I have subclassed the UITableViewCell and overridden the highligh and selected methods to not change the background color of selected subviews, but it is quite a nasty 'hack'Grinnell
can anyone explain how this sub classing thing works ? where should we put this code ? in same viewController class or a separate class ?Capparidaceous
Works like a charm (and is one of these WTF moments in iOS development ...).Hedjaz
C
5

I may be mistaken, but I couldn't find away to directly override an existing getter/setter in Swift. Building off user479821's answer, I found a workaround that seems to produce the desired results. I added the IBDesignable/IBInspectable annotations in case you use storyboard, which render's the final color in the editor.

@IBDesignable
class PersistentBackgroundLabel: UILabel {
    @IBInspectable var persistentBackgroundColor: UIColor = UIColor.clearColor() {
    didSet {
        super.backgroundColor = persistentBackgroundColor
    }
    }

    override var backgroundColor: UIColor? {
    didSet {
        if backgroundColor != persistentBackgroundColor {
            backgroundColor = persistentBackgroundColor
        }
    }
    }
}
Crankcase answered 31/3, 2015 at 3:43 Comment(0)
M
3

I got same problem and I guess it is sort of a UIKit framework bug. Thanks God I got a workaround: Order matters!!! Just follow the sequence:

- (void)tableView:(UITableView *)t willDisplayCell:(UITableViewCell*)c forRowAtIndexPath:(NSIndexPath *)i {
UIColor *bgc = [UIColor redColor];
// Set up the cell in following order:
c.textLabel.backgroundColor = bgc;
c.backgroundColor = bgc;
c.textLabel.text = @"foo";
}

I don't know why, but this sequence works fine and other order makes it appear as if c.textLabel.backgroundColor was forced to clearColor in some cells after deselecting them.

It was not a random behavior, it happened the first time the cells were reused, not when they were created, nor when they were secondly reused. With the workaround it works fine always.

Morphophoneme answered 6/12, 2011 at 0:28 Comment(1)
This worked for me too. Not sure why setting cell bg first doesn't work but changing the sequence made a difference.Mcallister
D
2

Set background color to label.layer.backgroundColor can fix this.

It seems cell will change backgroundColor of UILabel when highlighting.

Dionnedionysia answered 3/7, 2015 at 9:20 Comment(0)
G
1

I just create a flag in UILabel subclass to disable background color change after awakeFromNib or init. This allows the initial color set in storyboard to takes effect. And we don't have to call any extra methods.

@implementation MWPersistentBGLabel {
    BOOL disableBackgroundColorChange;
}

- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        [self setup];
    }
    return self;
}

- (void)awakeFromNib {
    [super awakeFromNib];
    [self setup];
}

- (void)setup {
    // disable background color change after setup is called
    disableBackgroundColorChange = YES;
}

// if we ever have to change the color later on, we can do so with this method
- (void)setPersistentBackgroundColor:(UIColor*)color {
    [super setBackgroundColor:color];
}

- (void)setBackgroundColor:(UIColor *)color {
    if (!disableBackgroundColorChange) {
        [super setBackgroundColor:color];
    }
    // do nothing - background color never changes
}

@end
Galitea answered 5/2, 2014 at 18:51 Comment(0)
N
0

In my apps i had to change the uitableviewcell selection style blue color, so i had to set uiimage view, when i clicked the cell is highlighted as Imageview. And i removed the highlighted of the cell when i returned to the view. And i couldnt understand your problem clearly. So just given my code and Try this one,

   cellForRowAtIndexPath Method:

CGRect a=CGRectMake(0, 0, 300, 100);
UIImageView *bImg=[[UIImageView alloc] initWithFrame:a];
bImg.image=[UIImage imageNamed:@"bg2.png"]; 
[bImg setContentMode:UIViewContentModeScaleToFill];
cell.selectedBackgroundView=bImg;
[bImg release];


   -(void)viewWillAppear:(BOOL)animated {
  [super viewWillAppear:YES];

  NSIndexPath *deselect = [self.tableView indexPathForSelectedRow];
  [self.tableView deselectRowAtIndexPath:deselect animated:NO];

   }

Best Of Luck

Nellnella answered 3/6, 2010 at 11:6 Comment(0)
G
0

I had to subclass the UItableView, create a list of tags of the view that I want to not make transparent background, and override the setHighlighted:animated: method so that it reset the specific labels background colour. longwinding and fidely, if only I had the source code t the UItableViewCell's actual class.

Grinnell answered 3/6, 2010 at 14:4 Comment(0)
S
-1

I couldn't get the accepted answer to work; not that I think the answer is incorrect (far from it - that appears to be the Right Way), but as I was writing my first iOS app my head was spinning with subclasses already. So I decided to cheat.

Let's say the custom cell was controlled by a TableViewCell class. I created a single pixel .png file of the correct background colour and created a UIImageView object in my custom cell. I used the Attributes inspector to set the default image and used 'Scale To Fill'. For a little more visual appeal, I then added the following to the User Defined Runtime Attributes in the Identity inspector:

KeyPath                Type         Value
layer.cornerRadius     Number       4
layer.masksToBounds    Boolean      YES

Voilá, rounded corners on the cheap.

Positioned directly behind the UILabel, it looks the business, though it obviously won't resize with content (as the only content is its own image). Not a problem for me as the data to be displayed had to be a fixed size anyway.

On some values it was good to have a different colour, which can be set really easily:

cell.deviceDetailBackground.image = [UIImage imageNamed:@"detailBackground2.png"];

Where 'cell' is the incarnation of my custom cell in the cellForRowAtIndexPath method, created using TableViewCell *cell;. No data to display?

cell.deviceDetailBackground.image = nil;

I'm sure there will be a good reason why this is a daft idea, but as I'm just starting out with iOS development this was an easy fix that worked for me. Feel free to tell me why not to do it!

Salic answered 18/3, 2013 at 15:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.