12

I want to use the default highlight on a UITableViewCell when it is tapped. However, I do not want custom subviews (and their subviews) to receive the message to update their highlighted states and therefore disrupt the backgroundColor property.

Edit
By "subview" I mean any UIView subclass, not just UITableViewCells.

Perhaps this hypothetical situation will better articulate what I'm looking for: I have one UITableViewCell. Call it c. I then add one UIView (call it v) as a subview of c. When I tap c, I want c to become highlighted (standard blue background with white font color), but I do not want v to become highlighted. How do I make this happen?

Jacob Barnard
  • 1,285
  • 1
  • 11
  • 23
  • 1
    **bump** i'd really like to know a way to do this as well! – jasongregori Jun 22 '11 at 22:06
  • For those of you who have or will responded/respond with answers regarding setting `UITableViewCellSelectionStyle` to `UITableViewCellSelectionStyleNone`, *this will not work!* Please take a closer read at the question. Thank you. – Jacob Barnard Jul 06 '11 at 23:59
  • 1
    The title of this question should be: How do you disable automatic highlighting of UITableViewCell subviews on selection. Current title is misleading. – orj Apr 11 '13 at 06:18

12 Answers12

6

I have a class which inherits from UITableViewCell, so i fixed it overriding setSelected:animated like this:

   - (void)setSelected:(BOOL)selected animated:(BOOL)animated
   {
       [super setSelected:selected animated:animated]; 
       //Reset highlighted status to all the childs that i care for.
       [self.someChild setHighlighted:NO];
       [self.someOtherChild setHighlighted:NO];
   }
albertein
  • 23,752
  • 5
  • 51
  • 57
  • This is a reasonable solution if you're not doing much customising of the cell and want default UITableViewCellSelectionStyle behaviour except on a few key subviews. – orj Apr 11 '13 at 06:02
  • This is what the questioner wants I think. – orj Apr 11 '13 at 06:10
  • I wanted to love this solution, but when using it, the subviews still highlight for a fraction of a second. It's very quick, but it's there. – Ryan Ballantyne Jun 12 '13 at 03:13
6

First of all, UITableView enumarates all the subviews, and sends them highlight messages.

So even if you put a UILabel in your view, no matter how deep it is, it traverses all views (by using subviews property).

One solution can be (which is IOS4+), overriding subviews property, and cheat tableview's highlight function that we do not have any subviews. To do that we need to determine the caller, and if it is tableview's highlight method, we should return no subviews at all.

We can create a simple UIView subclass and override subviews like below.

- (NSArray *)subviews{
    NSString* backtrace = [NSString stringWithFormat: @"%@",[NSThread callStackSymbols]];
    if ([backtrace rangeOfString:@"_updateHighlightColorsForView"].location!=NSNotFound)
        return [super subviews];   

    return [[NSArray new] autorelease];
}
  • callStackSymbols is available after IOS4+
  • _updateHighlightColorsForView is the UITableView's method, responsible for highlighting all children
Deniz Mert Edincik
  • 4,291
  • 19
  • 24
  • 2
    wow, that's pretty crazy. i didn't know you could do that. sounds too hacky though. – jasongregori Jul 12 '11 at 22:36
  • jason, yeah it is a cheat :) As tableview parses all view hierarchy, and sends each view a message, I guess that's the only way – Deniz Mert Edincik Jul 13 '11 at 11:17
  • 1
    definitely leaves itself up for breaking if the internals of UITableView change - though i count that as a high improbability, certainly is a quick fix for your problem, though – bshirley Jul 14 '11 at 22:55
  • 4
    DO NOT do what this answer describes. Just set selectionStyle to UITableViewCellSelectionStyleNone when creating your UITableViewCell. You will have to do your own selection styling but this should be pretty trivial, just override setSelected on your UITableViewCell subclass and adjust the sub view selection states. – orj Apr 11 '13 at 05:58
  • Though re-reading the question I realise that changing the selection style won't work. @albertein provides the right answer below: http://stackoverflow.com/a/15555620/20480 – orj Apr 11 '13 at 06:12
  • 1
    This answer is absolutely terrible. – Jessedc Apr 11 '13 at 06:19
3

Use UITableViewCellSelectionStyleNone on the table cells.

See the apple API documentation.

orj
  • 12,296
  • 12
  • 61
  • 72
user216592
  • 282
  • 1
  • 4
  • This is the correct way of turning off the automatic highlight of subviews on selection of the table cell. You obviously now have to do your own row selection styling. But that is pretty easy. – orj Apr 11 '13 at 05:57
  • However this isn't the answer the questioner wants. They want nearly default selection/highlighting behaviour. – orj Apr 11 '13 at 06:05
3

I solved this problem by overriding -(void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated like this (only works if the subview is a subclass of UIControl):

-(void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated {

    BOOL subviewWasEnabled = mySubview.enabled; //check if the view is enabled
    mySubview.enabled = NO; //disable it anyways

    [super setHighlighted:highlighted animated:animated];

    mySubview.enabled = subviewWasEnabled; //enable it again (if it was enabled)
}
mkeiser
  • 955
  • 9
  • 17
1

I didn't want any of the subviews to be highlighted. My solution was to set the selectionstyle to UITableViewCellSelectionStyleNone and to mimic the default selection behaviour as follows (overriding setSelected on a custom sub class of UITableViewCell):

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {

    int backgroundViewTag = 888;
    UIView *backgroundView = [self viewWithTag:backgroundViewTag];

    if (selected) {
        if (!backgroundView) {
            backgroundView = [[[UIView alloc] initWithFrame:self.bounds] autorelease];
            backgroundView.tag = backgroundViewTag;
            backgroundView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
            backgroundView.backgroundColor = [UIColor blueColor];
            backgroundView.alpha = 0.0;
            [self insertSubview:backgroundView atIndex:0];
        }

        if (animated) {
            [UIView animateWithDuration:0.5 animations:^{
                backgroundView.alpha = 1.0;
            }];
        } else {
            backgroundView.alpha = 1.0;
        }
    } else if (backgroundView) {
        if (animated) {
            [UIView animateWithDuration:0.5 animations:^{
                backgroundView.alpha = 0.0;
            } completion:^(BOOL finished) {
            }];
        } else {
            backgroundView.alpha = 0.0;
        }
    }
    [super setSelected:selected animated:animated];
}
Werner Altewischer
  • 8,904
  • 4
  • 47
  • 54
1

Recently I was looking for the same approach an to be honest I couldn't find a way to programmatically do this, so I kind of cheated my way out of this one.

Since highlighting respects images I ended up using a UIImageView filing the entire frame of my UIView and assigning a blank image to that and draw the rest of the view above the UIImageView. Your UIView will still be highlighted but you won't be able to see it because there will be a blank image above!

I hope this helps, I know this is probably not the best approach but got me the results I required

Ponchotg
  • 1,175
  • 1
  • 14
  • 25
1

Override -(void)setHighlighted:(BOOL)highlight; method in your UIControl subclass so that it does nothing. In the case of a UIButton subclass, you can do:

- (void)setHighlighted:(BOOL)highlighted {
    return;
}
SK9
  • 29,437
  • 32
  • 112
  • 154
0

Just put yours views inside a UIButton and they aren't updating on highlighting. You can't do that with xib of storyboard only on runtime.

UIButton *button = [[UIButton alloc] initWithFrame:0, 0, cellWidth, cellHeight];
[button addSubview:anyView]; // This view don't change his background color
[cell addSubview:button];
iUrii
  • 4,212
  • 1
  • 12
  • 17
0

May be we can change the highlighted state of subviews to match their default view.

That way even if it changes to highlighted state it will look to be in default state.

Not sure if it works, can you describe subviews more.

Tejesh Alimilli
  • 1,782
  • 1
  • 21
  • 30
0

I think you need to either disable the subviews (likely undesirable) or subclass the subviews to override this behavior.

bshirley
  • 7,674
  • 1
  • 31
  • 38
0

Maybe if you subclass your subview and override the setHighlighted method to do nothing or override the highlighted method to return always NO.

But UIView doesn't have the highlighted state, what kind of UIView childs you add to your cell ?

Johnmph
  • 3,337
  • 21
  • 31
0

So maybe a kind of this :

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];

m_colors = [[NSMutableArray alloc] init];

for (UIView *view in [cell.contentView subviews]) {
    [m_colors addObject:view.backgroundColor];
}

return indexPath;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];

for (int x = 0; x < [m_colors count]; ++x) {
    [[[cell.contentView subviews] objectAtIndex:x] setBackgroundColor:[m_colors objectAtIndex:x]];
}

[m_colors release];
m_colors = nil;
}
Johnmph
  • 3,337
  • 21
  • 31