ios 具有自动布局的 UITableViewCell 中的 UILabel 高度错误

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23664212/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 00:08:36  来源:igfitidea点击:

UILabel in UITableViewCell with auto layout has wrong height

iosuitableviewautolayout

提问by Steven Vandeweghe

I have a UITableViewwith cells that have a fixed height of 100 points. The cells are created in a xib file that uses 3 constraints to pin a UILabelto the left, right and top edges of the cell's contentView. The label's vertical hugging priority is set to 1000 because I want the cell's height to be as small as possible.

我有一个UITableView固定高度为 100 点的单元格。这些单元格是在一个 xib 文件中创建的,该文件使用 3 个约束将 a 固定UILabel到单元格的contentView. 标签的垂直拥抱优先级设置为 1000,因为我希望单元格的高度尽可能小。

When the width of the cell in the xib file is set to 320 points, the same as the tableView's width on the iPhone, autolayout works as expected. However, when I set the width of the cell to less than 320 points, I get unexpected results. (I want to use the same cell in tableViews that have different widths, e.g. in a universal app)

当xib 文件中单元格的宽度设置为320 点时,与iPhone 上tableView 的宽度相同,自动布局按预期工作。但是,当我将单元格的宽度设置为小于 320 点时,会得到意想不到的结果。(我想在具有不同宽度的 tableViews 中使用相同的单元格,例如在通用应用程序中)

For example: when I set the width to 224 points and give the label a text that takes up 2 lines at that width, the label's height will increase to fit the 2 lines, but when the cell is then resized to 320 points to fit in a tableView of that width, the text only takes up 1 line, but the height of the label remains at 2 lines.

例如:当我将宽度设置为 224 点并为标签提供一个在该宽度下占据 2 行的文本时,标签的高度将增加以适应 2 行,但是当单元格然后调整为 320 点以适应时一个那个宽度的tableView,文本只占1行,但标签的高度保持在2行。

I have put a sample project on GitHub to demonstrate the problem: https://github.com/bluecrowbar/CellLayout

我在 GitHub 上放了一个示例项目来演示这个问题:https: //github.com/bluecrowbar/CellLayout

Is there a way to make the UILabelalways resize to hug its text content?

有没有办法让UILabel总是调整大小以拥抱其文本内容?

回答by Steven Vandeweghe

Adding this in the cell subclass works:

在单元格子类中添加这个工作:

- (void)layoutSubviews
{
    [super layoutSubviews];
    [self.contentView layoutIfNeeded];
    self.myLabel.preferredMaxLayoutWidth = self.myLabel.frame.size.width;
}

I found this on http://useyourloaf.com/blog/2014/02/14/table-view-cells-with-varying-row-heights.html.

我在http://useyourloaf.com/blog/2014/02/14/table-view-cells-with-variing-row-heights.html上找到了这个。

Update 1:This answer was for iOS 7. I find auto layout in table view cells to be very unreliable since iOS 8, even for very simple layouts. After lots of experimentation, I (mostly) went back to doing manual layout and manual calculation of the cell's height.

更新 1:此答案适用于 iOS 7。我发现自 iOS 8 以来,表格视图单元格中的自动布局非常不可靠,即使对于非常简单的布局也是如此。经过大量实验后,我(大部分)回到手动布局和手动计算单元格的高度。

Update 2:I've run some tests on iOS 9 and it seems that UITableViewAutomaticDimensionfinally works as advertised. Yay!

更新 2:我已经在 iOS 9 上运行了一些测试,似乎UITableViewAutomaticDimension最终如宣传的那样工作。好极了!

回答by Thomás Calmon

Stupid bug! I've lost almost one day in this problem and finally I solved It with Steven Vandewghe's solution.

愚蠢的错误!我已经在这个问题上迷失了将近一天,最后我用 Steven Vandewghe 的解决方案解决了它。

Swift version:

迅捷版:

override func layoutSubviews() {
    super.layoutSubviews()
    self.contentView.layoutIfNeeded()
    self.myLabel.preferredMaxLayoutWidth = self.myLabel.frame.size.width
}

回答by Timothy Moose

Since you're constraining the label's width, the intrinsicContentSizehonors that widthand adjusts the height. And this sets up a chicken and egg problem:

由于您限制了标签的width,因此intrinsicContentSize尊重width并调整height. 这就产生了一个鸡和蛋的问题:

  1. The cell's Auto Layout result depends on the label's intrinsicContentSize
  2. The label's intrinsicContentSizedepends on the label's width
  3. The label's widthdepends on the cell's Auto Layout result
  1. 单元格的自动布局结果取决于标签的 intrinsicContentSize
  2. 标签intrinsicContentSize取决于标签width
  3. 标签width取决于单元格的自动布局结果

So what happens is that the cell's layout is only calculated once in which (2) is based on the static width in the XIB file and this results in the wrong label height.

所以发生的情况是单元格的布局只计算一次,其中 (2) 基于 XIB 文件中的静态宽度,这会导致错误的 label height

You can solve this by iterating. That is, repeat the Auto Layout calculation after the label's widthhas been set by the first calculation. Something like this in your custom cell will work:

你可以通过迭代来解决这个问题。也就是说,width在第一次计算设置标签后重复自动布局计算。您的自定义单元格中的类似内容将起作用:

- (void)drawRect:(CGRect)rect
{
    CGSize size = self.myLabel.bounds.size;
    // tell the label to size itself based on the current width
    [self.myLabel sizeToFit];
    if (!CGSizeEqualToSize(size, self.myLabel.bounds.size)) {
        [self setNeedsUpdateConstraints];
        [self updateConstraintsIfNeeded];
    }
    [super drawRect:rect];
}

original solutiondoes not work reliably:

原始解决方案不能可靠地工作:

- (void)layoutSubviews
{
    [super layoutSubviews];
    // check for need to re-evaluate constraints on next run loop
    // cycle after the layout has been finalized
    dispatch_async(dispatch_get_main_queue(), ^{
        CGSize size = self.myLabel.bounds.size;
        // tell the label to size itself based on the current width
        [self.myLabel sizeToFit];
        if (!CGSizeEqualToSize(size, self.myLabel.bounds.size)) {
            [self setNeedsUpdateConstraints];
            [self updateConstraintsIfNeeded];
        }
    });
}

回答by John Stephen

I'm using XCode 10 with iOS 12 and I still get autolayout problems with cells not being given the correct height when the table is first presented. Timothy Moose's answer didn't fix the problem for me, but based on his explanation I came up with a solution which does work for me.

我正在将 XCode 10 与 iOS 12 一起使用,但我仍然遇到自动布局问题,即第一次显示表格时单元格没有得到正确的高度。Timothy Moose 的回答并没有解决我的问题,但根据他的解释,我想出了一个对我有用的解决方案。

I subclass UITableViewController and override the viewDidLayoutSubviews message to check for width changes, and then force a table update if the width does change. This fixes the problem before the view is presented, which makes it look much nicer than my other efforts.

我子类化 UITableViewController 并覆盖 viewDidLayoutSubviews 消息以检查宽度更改,然后如果宽度确实更改则强制更新表格。这在呈现视图之前解决了问题,这使得它看起来比我的其他努力要好得多。

First add a property to your custom UITableViewController subclass to track the previous width:

首先向您的自定义 UITableViewController 子类添加一个属性以跟踪先前的宽度:

@property (nonatomic) CGFloat previousWidth;

Then override viewDidLayoutSubviews to check for width changes:

然后覆盖 viewDidLayoutSubviews 以检查宽度变化:

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];

    CGFloat width = self.view.frame.size.width;
    if (self.previousWidth != width) {
        self.previousWidth = width;
        [self.tableView beginUpdates];
        [self.tableView endUpdates];
    }
}

This fixed issues with my table cells sometimes being given the wrong height initially.

这解决了我的表格单元格最初有时会给出错误高度的问题。

回答by Maria

I usually add these two lines to viewDidLoad()

我通常将这两行添加到 viewDidLoad()

    self.tableView.rowHeight = UITableViewAutomaticDimension
    self.tableView.estimatedRowHeight = 96

This will automatically resize the cell

这将自动调整单元格的大小