UITableView 自动调整行约束在 iPhone 6Plus 上神秘地打破

Posted

技术标签:

【中文标题】UITableView 自动调整行约束在 iPhone 6Plus 上神秘地打破【英文标题】:UITableView auto resizing row constraint breaking mysteriously on iPhone 6Plus 【发布时间】:2015-08-23 22:40:06 【问题描述】:

我有一个自定义 UITableViewCell,它有一个缩略图和一堆文本。行高配置为使用

自动计算
tableView.estimatedRowHeight = 129;
tableView.rowHeight = UITableViewAutomaticDimension

行高应精确计算为 138 点。 在 iPhone 5 上一切看起来都很棒。但是,在 iPhone 6 Plus 上,对于随机行,自动行高会间歇性失败,并显示以下日志。

(
    "<NSLayoutConstraint:0x17009ddd0 V:|-(20)-[scoop.ThumbnailImage:0x124d2a5a0]   (Names: '|':UITableViewCellContentView:0x124e23200 )>",
    "<NSLayoutConstraint:0x17009de70 UITableViewCellContentView:0x124e23200.bottomMargin == scoop.ThumbnailImage:0x124d2a5a0.bottom + 20>",
    "<NSLayoutConstraint:0x17009e780 V:[scoop.ThumbnailImage:0x124d2a5a0(90)]>",
    "<NSLayoutConstraint:0x17009ef00 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x124e23200(138.333)]>"
)

日志的最后一行似乎说由于某种原因,行高被计算为 138.333 而不是 138。我现在一直在敲我的头,但我无法弄清楚为什么会这样。有人可以帮忙吗?

更新:这就是我的表格视图单元格的样子。

更新我无法从主仓库中获取代码,因为它是一个更大项目的一部分。但是我已经设法通过一个非常简单的理智项目重现了这个问题。请在on github找到它。

【问题讨论】:

你能贴出计算单元格高度的代码吗? 我正在使用 tableView.estimatedRowHeight = 129; tableView.rowHeight = UITableViewAutomaticDimension 来计算我的控制器 viewDidLoad 中的行高。 仍然,如果它是完全动态的,则应该没有错误。即使它不完全是 168。您是否暗示您在单元格内的视图的设置方式是,如果您将它们的所有高度相加,它正好是 168? 缩略图被配置为距离我的单元格的左上角和下边缘 20 点。缩略图高度本身是 108 点。将所有空格加起来,缩略图高度等于 168。至少这是我期望的动态行高。 是否显示错误?那么文本标签呢?我假设它们嵌入在 UIView 中。你设置它的高度还是根据里面标签的高度计算出来的? 【参考方案1】:

此警告告诉您您的约束存在冲突。 将高度约束的优先级降低到 999,它将消失。在您的 Github 项目中对其进行了测试,并且运行良好。

【讨论】:

这行得通,但它仍然意味着约束在某种程度上被打破了,不是吗? 这意味着自动布局不能满足它,但它会尽可能接近。您的数学以某种方式关闭,但使用自动布局,您甚至不应该在大多数情况下使用明确的高度 当显式高度不适合自动布局时,设置较低的优先级会告诉它忽略此特定约束并继续前进。这就是优先级的目的——避免不同场景中的冲突 是的,使其约束的优先级小于其行的内容视图解决了我的问题。谢谢!【参考方案2】:

在 3 倍比例显示器(iPhone 6+ 是)上的 0.333 可能与单元格分隔符相连。

请注意,您的约束不会设置单元格的大小,而是设置contentView 的大小。但是单元格必须为单元格分隔符的单元格高度添加 2 个像素(= 0.666 点)。自动布局尝试将视图位置保持在整数边界上,因此将 0.666 点添加到单元格高度可能会导致内容高度增加 0.333。

您可以通过将表格分隔符设置为None 来避免该错误。尽管按照另一个 answer 的建议将其中一个优先级设置为 999(通常是最低优先级)通常是一个很好的解决方案。

【讨论】:

【参考方案3】:

警告会准确地告诉您问题出在哪里,但您可能没有意识到这一点。前三个约束适用于 90 像素高的图像,该图像在其容器顶部下方 20 像素处,在其容器底部上方 margin 上方 20 像素处。那是 130,这与第四个约束不兼容,它希望总高度为 138。但是,由于底部边缘约束是相对于容器的 margin 的,因此会增加一定数量的像素。要么删除总高度限制(我的建议),要么更改顶部和底部边缘量。

【讨论】:

底部被限制在边距,这将增加额外的 8 个点。所以总数是 138。问题在于 tableView.rowHeight = UITableViewAutomaticDimension 计算的额外 0.333。在 iPhone 5 上,它正确计算出高度为 138 点。 我刚刚下载了你的项目,首先突出的是情节提要中有两个布局错误:Pink Floyd 图像和标签没有y 位置。我要放一些进去。 好的,我知道了!首先,我将图标的底部约束设置为 9,而不是 10,这使它更接近 contentView 想要的 109 像素高度。但是,我也遇到了奇怪的舍入误差,就像你在额外的 0.333 中看到的那样。我通过将底部约束的优先级降低到 500 来修复它,这样它就不会与单元格试图强制执行的 109 高度冲突。另请参阅***.com/questions/23308400/…。 我认为 contentHeight 如何计算它想要的总高度是一个错误。 @suparngp 根据我的经验,提及封装高度约束的约束冲突警告通常是由UITableView 自身逻辑中的transient 约束冲突状态引起的。在UITableView 第一次创建单元格后,它的默认高度安装为约束。当它调用systemLayoutSizeFittingSize: 来调整 contentView 的大小时,该方法的执行会发出错误,但 UITV 会正确调整大小。因为这是一个暂时性问题,所以降低优先级并不意味着您接受了不正确的单元格布局。你只是在解决一个虚假的警告。

以上是关于UITableView 自动调整行约束在 iPhone 6Plus 上神秘地打破的主要内容,如果未能解决你的问题,请参考以下文章

如何强制 uitableview 调整单元格的大小(在停用高度约束后)?

UITableview 没有在 iOS 中使用自动布局调整大小

在 UITableView 标头中将标签约束设置为 0 时自动布局失败

动画 UITableView 的自动布局顶部约束导致崩溃,有啥线索吗?

UITableView 标题部分的高度不会为自定义 UIView() 类自动调整

带有约束更新的 UITableViewCell 导致 UITableView 跳来跳去