ios8 autolayout: BOTH multi-line(maybe 0 line) lab

2019-05-10 04:23发布

问题:

I wanna display two UILabels(Title, Subtitle) in a cell.
for Title: multiple line > 0
for Subtitle: 0 multiple line 2

A bug here(say, title&subtitle are both 2 lines, cell's indexPath.row = 1):
The first time I run the simulator, title only shows 1 line and subtitle shows 2 lines. After I scrolled the tableView and back to the first indexPath.row, it display correctly! It seems like this:

First time:
—————————————————
This is the tile, and it should display...

This is the subtitle, and it should show
2 rows.

—————————————————

After scroll and back to this cell:
—————————————————
This is the title, and it should display
two rows.

This is the subtitle, and it should show
2 rows.

—————————————————

What I've done:
In controller:
tableView.estimatdRowHeight = 79
tableView.rowHeight = UITableViewAutomaticDimension

In storyboard:
For title:

  1. Leading space to superview
  2. Trailing space to superview
  3. Top space to Superview
  4. Align leading to Subtitle
  5. Align trailing to Subtitle
  6. Bottom space to Subtitle

For subtitle:

  1. Bottom space to superview
  2. Align Leading to Title
  3. Align trailing to Title
  4. Top space to Title

I'm confused for this bug several days, any ideas to solve this? Big thanks!!!(Sorry for lacking image cuz I don't get enough reputation ><)

回答1:

Cells that are loaded from a storyboard don't start out with the right initial width.

This is why the label isn't sized properly the first time, but appears correctly once you (reload the data, or) scroll the cell off-screen, then on-screen.

Since the cell width is initially incorrect, the label ends up using a preferredMaxLayoutWidth which is wider than the table. (The label thought it had more room to fit everything on one line.)

The solution which worked for me was to make sure my (subclassed) cell's width matched the tableView's width:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];

    [cell adjustSizeToMatchWidth:CGRectGetWidth(self.tableView.frame)];

    [self configureCell:cell forRowAtIndexPath:indexPath];

    [cell setNeedsUpdateConstraints];
    [cell updateConstraintsIfNeeded];

    return cell;
}

In TableViewCell.m:

- (void)adjustSizeToMatchWidth:(CGFloat)width
{
    // Workaround for visible cells not laid out properly since their layout was
    // based on a different (initial) width from the tableView.

    CGRect rect = self.frame;
    rect.size.width = width;
    self.frame = rect;

    // Workaround for initial cell height less than auto layout required height.

    rect = self.contentView.bounds;
    rect.size.height = 99999.0;
    rect.size.width = 99999.0;
    self.contentView.bounds = rect;
}

I'd also recommend checking out smileyborg's excellent answer about self-sizing cells, along with his sample code. It's what tipped me off to the solution, when I bumped into the same issue you are having.