Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 739
sash Avatar asked Jul 06 '15 12:07

sash


3 Answers

I solved this problem using systemLayoutSizeFittingSize:withHorizontalFittingPriority:verticalFittingPriority:.

In my case, I wanted to calculate a cell's height, so I've set the horizontal priority to UILayoutPriorityRequired and the vertical one to UILayoutPriorityFittingSizeLevel, and it worked:

[myView systemLayoutSizeFittingSize:mySize withHorizontalFittingPriority:UILayoutPriorityRequired verticalFittingPriority:UILayoutPriorityFittingSizeLevel];
like image 129
Klein Mioke Avatar answered Nov 17 '22 20:11

Klein Mioke


Calling

[self.contentView layoutIfNeeded]; 

in layoutSubviews of the cell, fixed the issue.

Source Table View Cells With Varying Row Heights

like image 11
sash Avatar answered Nov 17 '22 20:11

sash


You can use this class to solve all problems with your UILabel and Auto Layout:

class UILabelPreferedWidth : UILabel {
    override var bounds: CGRect {
        didSet {
            if (bounds.size.width != oldValue.size.width) {
                self.setNeedsUpdateConstraints()
            }
        }
    }

    override func updateConstraints() {
        if (self.preferredMaxLayoutWidth != bounds.size.width) {
            self.preferredMaxLayoutWidth = bounds.size.width
        }

        super.updateConstraints()
    }
}
like image 5
Grzegorz Krukowski Avatar answered Nov 17 '22 22:11

Grzegorz Krukowski