Byron Cox
Byron Cox

Reputation: 349

UITableViewCell subview not being displayed when the table is first displayed

I am trying to add a strikethrough label to my table cells (conditional on a BOOL hasStrikethrough). The problem is that the strikethrough does not appear when the table is first displayed (even though hasStrikethrough == YES). If you scroll the table then the rows get redisplayed and the strikethrough appears correctly. The strikethrough is just a UILabel that is being added as a subview of the UITableViewCell.

Here is my code for cellForRowAtIndexPath:

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

static NSString *CellIdentifier = @"ItemCell";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

if (cell==nil) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}


Item  *item = [self.fetchedResultsController objectAtIndexPath:indexPath];

cell.textLabel.text = item.itemName;
cell.textLabel.textAlignment = UITextAlignmentLeft;
cell.showsReorderControl = YES;
cell.shouldIndentWhileEditing = NO;

if ([[item hasStrikethrough] boolValue] == YES) {
    [self addStrikethrough:cell];
}

return cell;
}

Here is the code for addStrikethrough:

- (void)addStrikethrough:(UITableViewCell*)cell
{
CGRect frame = cell.textLabel.frame;
UILabel *strikethrough = [[UILabel alloc] initWithFrame:frame];
strikethrough.opaque = YES;
strikethrough.backgroundColor = [UIColor clearColor];
strikethrough.text = @"------------------------------------------------";
strikethrough.lineBreakMode = UILineBreakModeClip;
[cell addSubview:strikethrough];
}

Thanks in advance :-)

Upvotes: 0

Views: 2413

Answers (2)

Eyal
Eyal

Reputation: 10828

The problem is with the line CGRect frame = cell.textLabel.frame;
The cell's textLabel didn't laid out yet, so the frame will be (0,0,0,0) and u won't see the strikethrough label.

The reason u see the strikethrough in the next cells is because those are the reused cells that already laid out the textLabel.

As I see it u have two options:
First option, set the strikethrough frame yourself, u can use sizeWithFont to figure out what is the needed width, the font should be the textFiled font. Play with it a bit to find the correct x offset so it will be exactly on the textLabel.

- (void)addStrikethrough:(UITableViewCell*)cell
{
    CGSize textLabelSize = [cell.textLabel.text sizeWithFont:[UIFont systemFontOfSize:20.0]];

    CGFloat cellHeight = cell.bounds.size.height;
    CGFloat strikethroughLabelHeight = 20.0;

    CGRect frame = CGRectMake(12, (cellHeight - strikethroughLabelHeight)/2, textLabelSize.width, strikethroughLabelHeight);
    UILabel *strikethrough = [[UILabel alloc] initWithFrame:frame];
    strikethrough.opaque = YES;
    strikethrough.backgroundColor = [UIColor clearColor];
    strikethrough.text = @"------------------------------------------------";
    strikethrough.lineBreakMode = UILineBreakModeClip;
    [cell.contentView addSubview:strikethrough];
}  

Second option is to subclass UITableViewCell and add the strikethrough label to it.
then u can set it's frame in layoutSubviews method, and u can hide/unhide this label according to your needs...

Upvotes: 3

Kevin Grant
Kevin Grant

Reputation: 5431

The cell is reused based on its reuse identifier. Currently you're only using one identifier so "cell with no subview" looks the same as "cell with subview" to the OS.

Try checking the strikethrough condition at the beginning, and inventing a new reuse identifier (e.g. StrikeIdentifier) in that case.

Here is one approach that does what I'm suggesting:

Item *item = [self.fetchedResultsController objectAtIndexPath:indexPath];
BOOL isStrike = ([[item hasStrikethrough] boolValue]);

static NSString *CellIdentifier = @"ItemCell";
static NSString *StrikeIdentifier = @"ItemCellStrike";

UITableViewCell *cell = (isStrike)
                        ? [tableView dequeueReusableCellWithIdentifier:StrikeIdentifier]
                        : [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

if (cell==nil) {
    if (isStrike) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:StrikeIdentifier];
        [self addStrikethrough:cell];
    } else {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }
}

. . .

Upvotes: 1

Related Questions