UITabel在具有自动布局的UITableViewCell中具有错误的高度

时间:2014-05-14 20:10:42

标签: ios uitableview autolayout

我有UITableView个单元格,其固定高度为100磅。单元格在xib文件中创建,该文件使用3个约束将UILabel固定到单元格contentView的左,右和上边缘。标签的垂直拥抱优先级设置为1000,因为我希望单元格的高度尽可能小。

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

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

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

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

6 个答案:

答案 0 :(得分:66)

在单元子类中添加它可以起作用:

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

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

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

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

答案 1 :(得分:14)

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

Swift版本:

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

答案 2 :(得分:3)

由于您限制了标签widthintrinsicContentSize尊重width并调整height。这就产生了鸡和蛋的问题:

  1. 单元格的自动布局结果取决于标签' s intrinsicContentSize
  2. 标签intrinsicContentSize取决于标签&{39} width
  3. 标签width取决于单元格的自动布局结果
  4. 所以会发生的情况是,单元格的布局只计算一次,其中(2)基于XIB文件中的静态宽度,这会导致错误的标签height

    你可以通过迭代来解决这个问题。也就是说,在第一次计算设置标签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];
    }
    

    原始解决方案无法可靠地运行:

    - (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];
            }
        });
    }
    

答案 3 :(得分:0)

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

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

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

答案 4 :(得分:0)

我在iOS 12上使用XCode 10,但仍然出现自动布局问题,首次显示表格时,单元格的高度不正确。蒂莫西·穆斯(Timothy Moose)的回答并不能解决我的问题,但是根据他的解释,我想出了一个对我有用的解决方案。

我继承了UITableViewController的子类,并重写viewDidLayoutSubviews消息以检查宽度变化,如果宽度变化,则强制更新表。这样可以在显示视图之前解决该问题,使其看上去比我的其他工作要好得多。

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

@property (nonatomic) CGFloat previousWidth;

然后覆盖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];
    }
}

这解决了我的表格单元格有时最初被赋予错误的高度的问题。

答案 5 :(得分:0)

我知道这是一个老问题,但是也许UILabel子类也可以为某些问题提供帮助

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

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

注意:在UILabel在StackView内时无法正确调整自身大小的情况下也适用