Search code examples
objective-cuitableviewautolayoutuilabel

Wrong size returned by systemLayoutSizeFittingSize when using multiline label


I have a custom table cell MyCell, that has only 1 multiline label with constraints to the sides. The xib size is 320 x 280. enter image description here

I am using systemLayoutSizeFittingSize to calculate cell height based on the content:

- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
        MyCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MyCell"];

        // set cell width = table width
        CGRect rect = cell.frame;
        rect.size.width = CGRectGetWidth(tableView.frame);
        cell .frame= rect;

        // update the text
        cell.mainLabel.text = @"Some multiline text. Some multiline text. Some multiline text. Some multiline text. Some multiline text. Some multiline text. Some multiline text. Some multiline text.";

        [cell setNeedsLayout];
        [cell layoutIfNeeded];

        CGSize size = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];

        NSLog(@"size %@", NSStringFromCGSize(size)); // {290.5, 117.5}

        return size.height;
    }

MyCell layoutSubviews looks like this

- (void) layoutSubviews {
    [super layoutSubviews];

    NSLog(@"cell frame %@", NSStringFromCGRect(self.frame)); // {{0, 0}, {375, 280}}
    NSLog(@"self.mainLabel frame %@", NSStringFromCGRect(self.mainLabel.frame)); // {{8, 8}, {304, 264}}

    [self.mainLabel updatePreferredMaxLayoutWidth];
}

updatePreferredMaxLayoutWidth is category that updated preferredMaxLayoutWidth if the frame width is not the same as preferredMaxLayoutWidth

-(void)updatePreferredMaxLayoutWidth {
    if (self.numberOfLines == 0) {
        if ( self.preferredMaxLayoutWidth != self.frame.size.width){
            self.preferredMaxLayoutWidth = self.frame.size.width;
            [self setNeedsUpdateConstraints];
        }
    }
}

Now when I run I get output:

cell frame {{0, 0}, {375, 280}}

Cell size in layoutSubviews has the same width as the table view, correct

self.mainLabel frame {{8, 8}, {304, 264}}

self.mainLabel frame inside layoutSubviews is 304, that is equal to label size inside the xib file. So the label’s frame wasn't updated to the new cell's size. Why?

size {290.5, 117.5}

Size of systemLayoutSizeFittingSize that is completely wrong. What I have missed?


Solution

  • Calling

    [self.contentView layoutIfNeeded]; 
    

    in layoutSubviews of the cell, fixed the issue.

    Source Table View Cells With Varying Row Heights