如何在表视图中的UITableViewCells中使用“自动布局”,让每个单元格的内容和子视图确定行高度(自身/自动),同时保持平滑的滚动性能?


当前回答

只要你的单元格布局良好。

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];

    return [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
}

更新:您应该使用iOS 8中引入的动态调整大小。

其他回答

(对于底部读取的Xcode 8.x/Xcode 9.x)

注意Xcode 7.x中的以下问题,这可能是混淆的根源:

Interface Builder无法正确处理自动调整单元格大小的设置。即使你的约束绝对有效,IB仍然会抱怨,并给你令人困惑的建议和错误。原因是IB不愿意根据您的约束条件改变行的高度(以便单元格适合您的内容)。相反,它会保持行的高度不变,并开始建议您更改约束,您应该忽略这些约束。

例如,假设您已经设置好了一切,没有警告,没有错误,一切正常。

现在,如果您更改字体大小(在本例中,我将描述标签的字体大小从17.0更改为18.0)。

由于字体大小增加,标签现在希望占据3行(之前它占据2行)。

如果Interface Builder按预期工作,它将调整单元格的高度以适应新的标签高度。然而,实际发生的情况是IB显示红色的自动布局错误图标,并建议您修改拥抱/压缩优先级。

您应该忽略这些警告。相反,您可以*手动更改行的高度(选择“单元格”>“大小检查器”>“行高度”)。

我一次单击一次(使用上/下步进器)改变这个高度,直到红色箭头错误消失!(实际上,您会收到黄色警告,此时只需继续并执行“更新帧”,一切都应该正常)。

*请注意,您实际上不必在Interface Builder中解决这些红色错误或黄色警告-在运行时,一切都会正常工作(即使IB显示错误/警告)。只需确保在运行时控制台日志中没有出现任何自动布局错误。事实上,尝试总是更新IB中的行高度是非常令人讨厌的,有时几乎不可能(因为分数值)。为了防止烦人的IB警告/错误,您可以选择所涉及的视图,并在Size Inspector中为属性Ambiguity选择Verify Position Only


Xcode 8.x/Xcode 9.x看起来(有时)做的事情与Xcode 7.x不同,但仍然不正确。例如,即使抗压优先级/拥抱优先级设置为必需(1000),Interface Builder也可能拉伸或剪裁标签以适合单元格(而不是调整单元格高度以适合标签周围)。在这种情况下,它甚至可能不会显示任何自动布局警告或错误。或者,有时它完全像上面描述的Xcode7.x那样。

UITableView.automaticDimension可以通过接口生成器设置:

Xcode>情节提要>尺寸检查器

表格视图单元格>行高度>自动

我必须使用动态视图(通过代码设置视图和约束),当我想设置preferredMaxLayoutWidth标签的宽度为0时。所以我有错误的细胞高度。

然后我添加了

[cell layoutSubviews];

执行之前

[cell setNeedsUpdateConstraints];
[cell updateConstraintsIfNeeded];

之后,标签的宽度符合预期,动态高度计算正确。

假设您有一个带有子视图的单元格,并且希望该单元格的高度足够高,以包含子视图+填充。

1) 将子视图的底部约束设置为cell.contentView减去所需的填充。不要对单元格或cell.contentView本身设置约束。

2) 将tableView的rowHeight属性或tableView:heightForRowAtIndexPath:设置为UITableViewAutomaticDimension。

3) 将tableView的estimatedRowHeight属性或tableView:estimatedHeightForRowAtIndexPath:设置为高度的最佳猜测。

就是这样。

在我的例子中,填充是因为sectionHeader和sectionFooter的高度,故事板允许我将其更改为最小值1。因此,在viewDidLoad方法中:

tableView.sectionHeaderHeight = 0
tableView.sectionFooterHeight = 0