0

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 :-)

Byron Cox
  • 349
  • 5
  • 17

2 Answers2

3

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

Eyal
  • 10,777
  • 18
  • 78
  • 130
1

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

. . .
Kevin Grant
  • 5,363
  • 1
  • 21
  • 24
  • First I have tried this in cellForRowAtIndexPath:. I have taken the code from addStrikethrough: and placed it in an else statement added to if(cell==nil). I have hardcoded the cell.textLabel.text in the else statement to equal "DEQUEUED CELL". I commented out the conditional call to addStrikethrough:. When you run. the table shows rows with the text "DEQUEUED CELL" but no strikethrough? So every row is a dequeued cell and every row fails to show the strikethrough? Every cell should be having the subview added to it. No new cells are being created so there shouldn't be identifier confusion. – Byron Cox Jul 23 '12 at 03:39
  • I have added a code example to my answer to try to illustrate what I mean. You need the template cell to have everything that is needed to display its data because the OS will not ask you to create it every time. – Kevin Grant Jul 23 '12 at 03:54
  • Hi Kevin, thank you very much for looking at this. I have implemented the code that you have supplied but unfortunately it doesn't work for me. I have also hardcoded isStrike to YES to rule out that my core data is wrong. Again when I run, the cells are displayed without strikethrough. I have stepped through to ensure that addStrikethrough: is being called. Even if I scroll the rows the strikethrough does not appear (with my code it did). – Byron Cox Jul 23 '12 at 04:37
  • What you've done looks similar to tables I've made before...one difference is that my cells had custom background views where I set an autoresizing mask, e.g. `newView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleHeight;` and `cell.backgroundView = newView;`. I'm not sure if that detail is important. – Kevin Grant Jul 24 '12 at 02:31