Jonathan.
Jonathan.

Reputation: 55534

UITableViewCell makes label's background clear when highlighted

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?

Upvotes: 42

Views: 19443

Answers (10)

Vahan
Vahan

Reputation: 2186

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
}

Upvotes: 55

blunt sword
blunt sword

Reputation: 21

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

It seems cell will change backgroundColor of UILabel when highlighting.

Upvotes: 2

Conner Fromknecht
Conner Fromknecht

Reputation: 151

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

Upvotes: 5

Tommy
Tommy

Reputation: 594

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.

Upvotes: 47

Hlung
Hlung

Reputation: 14298

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

Upvotes: 1

roobarb_
roobarb_

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

Upvotes: -1

Pasky
Pasky

Reputation: 126

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.

Upvotes: 3

user479821
user479821

Reputation: 411

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.

Upvotes: 41

Jonathan.
Jonathan.

Reputation: 55534

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.

Upvotes: 0

Pugalmuni
Pugalmuni

Reputation: 9390

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

Upvotes: 0

Related Questions