AutoLayout row height miscalculating for NSAttribu

2019-03-09 04:22发布

My app pulls HTML from an API, converts it into a NSAttributedString (in order to allow for tappable links) and writes it to a row in an AutoLayout table. Trouble is, any time I invoke this type of cell, the height is miscalculated and the content is cut off. I have tried different implementations of row height calculations, none of which work correctly.

How can I accurately, and dynamically, calculate the height of one of these rows, while still maintaining the ability to tap HTML links?

Example of undesired behavior

My code is below.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    switch(indexPath.section) {
        ...
        case kContent:
        {
            FlexibleTextViewTableViewCell* cell = (FlexibleTextViewTableViewCell*)[TableFactory getCellForIdentifier:@"content" cellClass:FlexibleTextViewTableViewCell.class forTable:tableView withStyle:UITableViewCellStyleDefault];

            [self configureContentCellForIndexPath:cell atIndexPath:indexPath];
            [cell.contentView setNeedsLayout];
            [cell.contentView layoutIfNeeded];
            cell.selectionStyle = UITableViewCellSelectionStyleNone;
            cell.desc.font = [UIFont fontWithName:[StringFactory defaultFontType] size:14.0f];

            return cell;
        }
        ...
        default:
            return nil;
    }
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    UIFont *contentFont = [UIFont fontWithName:[StringFactory defaultFontType] size:14.0f];
    switch(indexPath.section) {
        ...
        case kContent:
            return [self textViewHeightForAttributedText:[self convertHTMLtoAttributedString:myHTMLString] andFont:contentFont andWidth:self.tappableCell.width];
            break;
        ...
        default:
            return 0.0f;
    }
}

-(NSAttributedString*) convertHTMLtoAttributedString: (NSString *) html {
    return [[NSAttributedString alloc] initWithData:[html dataUsingEncoding:NSUTF8StringEncoding]
                                            options:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
                                                      NSCharacterEncodingDocumentAttribute: @(NSUTF8StringEncoding)}
                                 documentAttributes:nil
                                              error:nil];
}

- (CGFloat)textViewHeightForAttributedText:(NSAttributedString*)text andFont:(UIFont *)font andWidth:(CGFloat)width {
    NSMutableAttributedString *mutableText = [[NSMutableAttributedString alloc] initWithAttributedString:text];

    [mutableText addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, text.length)];

    UITextView *calculationView = [[UITextView alloc] init];
    [calculationView setAttributedText:mutableText];

    CGSize size = [self text:mutableText.string sizeWithFont:font constrainedToSize:CGSizeMake(width,FLT_MAX)];
    CGSize sizeThatFits = [calculationView sizeThatFits:CGSizeMake(width, FLT_MAX)];

    return sizeThatFits.height;
}

8条回答
We Are One
2楼-- · 2019-03-09 04:59

If you can target iOS 8 using dynamic cell sizing is the ideal solution to your problem.

To use dynamic cell sizing, delete heightForRowAtIndexPath: and set self.tableView.rowHeight to UITableViewAutomaticDimension.

Here is a video with more details: https://developer.apple.com/videos/wwdc/2014/?include=226#226

查看更多
祖国的老花朵
3楼-- · 2019-03-09 05:08

You should be able to convert to an NSString to calculate the height like this.

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UIFont * font = [UIFont systemFontOfSize:15.0f];
    NSString *text = [getYourAttributedTextArray objectAtIndex:indexPath.row] string];
    CGFloat height = [text boundingRectWithSize:CGSizeMake(self.tableView.frame.size.width, maxHeight) options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading) attributes:@{NSFontAttributeName: font} context:nil].size.height;

    return height + additionalHeightBuffer;
}
查看更多
登录 后发表回答