rebellion
rebellion

Reputation: 6740

Add subview to UITableViewCell on selection

I'm trying to add a UIView that is supposed to strikethrough the text (don't worry about the horizontal misplacement).

However, when selecting a row, the line is added several rows below. Why?

Strange selection behaviour

Here's my code:

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"%@", indexPath);

    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    UILabel *label = cell.textLabel;

    CGSize textSize = [[label text] sizeWithAttributes:@{NSFontAttributeName:[label font]}];
    CGFloat strikeWidth = textSize.width;

    UIView *lineView = [[UIView alloc] initWithFrame:CGRectMake(self.view.bounds.size.height / 2, 200, strikeWidth, 2)];
    lineView.backgroundColor = [UIColor redColor];

    lineView.tag = 100;

    [cell.contentView addSubview:lineView];
}

Upvotes: 0

Views: 613

Answers (3)

Kujey
Kujey

Reputation: 1122

I think your line is appearing outside of your cell because you set an y origin of 200 in your frame, which seems pretty high.

Moreover, if you want to play with strikethrough in a UITableviewCell, you'd better not do it this way, because on multiple selection this 'strikethroughView' will be added multiple times, and never removed. Also on a tableview reloadData, or scrolling the cells are reused, and you don't want to see these strikethroughViews randomly displayed.

Here are two ways to do it properly :

  • Use the NSAttributedString framework. Basically if allows you to do all sorts of things to a string, like setting color, background color, paragraph style, but also strikeThrough. Here is what i would write in the didSelect delegate method :

    -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    NSString *string = cell.textLabel.text;
    
    NSDictionary *attributes = @{NSStrikethroughStyleAttributeName: @(NSUnderlineStyleThick)};
    NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:string attributes:attributes];
    cell.textLabel.attributedText = attributedString; 
    }
    
  • The other solution would be to add a Category on UICollectionViewCell and implement a "setStrikeTrough" method in it.

Hope it'll help.

Upvotes: 0

Mike
Mike

Reputation: 9835

Your problem is here:

UIView *lineView = [[UIView alloc] initWithFrame:CGRectMake(self.view.bounds.size.height / 2, 200, strikeWidth, 2)];

In this case, "self" is the tableViewController, not the label or the cell. What you're doing is setting the x origin of the view as half the height of the screen, the y origin down 200 points, with a width of strikeWidth and a height of 2.

Because the line view you are adding is going to be a subview of the cell, you always want to make the frame relative to it's superview, which in this case is the cell itself. You likely want to use something like similar to below:

CGRectMake(CGRectGetMinX(cell.textLabel.frame), CGRectGetHeight(cell.contentView.frame) / 2, strikeWidth, 2)

You'll likely want to tweak values to make it line up, but you get the idea...

EDIT: Better frame added and here's more code that does it nicely:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [tableView deselectRowAtIndexPath:indexPath animated:YES];

    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    UILabel *label = cell.textLabel;

    CGSize textSize = [[label text] sizeWithAttributes:@{NSFontAttributeName:[label font]}];
    CGFloat strikeWidth = textSize.width;

    UIView *lineView = [[UIView alloc] initWithFrame:CGRectMake(CGRectGetMinX(label.frame), CGRectGetHeight(cell.contentView.frame) / 2, strikeWidth, 2)];
    lineView.backgroundColor = [UIColor redColor];
    [cell.contentView addSubview:lineView];

    [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}

Upvotes: 0

KerrM
KerrM

Reputation: 5240

Instead of using a UIView and adding a subview to the cell, you should use an NSAttributedString for the cell text and the NSStrikethroughStyleAttributeName to strike through with an NSStrikethroughColorAttributeName for the strikethrough colour.

Upvotes: 2

Related Questions