这里的问题是多行标签'preferredMaxLayoutWidth
财产。该属性告诉标签何时应该自动换行。必须正确设置每个标签的顺序intrinsicContentSize
具有正确的高度,这最终是自动布局将用来确定单元格高度的。
Xcode 6 Interface Builder 引入了一个新选项,可以将此属性设置为自动的。不幸的是,存在一些严重的错误(从 Xcode 6.2/iOS 8.2 开始),从笔尖或 Storyboard 加载单元格时,无法正确/自动设置该错误。
为了解决这个错误,我们需要preferredMaxLayoutWidth
设置为恰好等于标签在表视图中显示后的最终宽度。实际上,我们希望在从以下位置返回单元格之前执行以下操作tableView:cellForRowAtIndexPath:
:
cell.nameLabel.preferredMaxLayoutWidth = CGRectGetWidth(cell.nameLabel.frame)
cell.idLabel.preferredMaxLayoutWidth = CGRectGetWidth(cell.idLabel.frame)
cell.actionsLabel.preferredMaxLayoutWidth = CGRectGetWidth(cell.actionsLabel.frame)
仅仅添加这段代码是行不通的,因为当这3行代码执行时tableView:cellForRowAtIndexPath:
,我们使用每个标签的宽度来设置preferredMaxLayoutWidth
-- 但是,如果您此时检查标签的宽度,则会发现标签宽度与显示单元格并布置其子视图后的宽度完全不同。
此时我们如何使标签宽度准确,以便它们反映最终宽度?这是将所有内容组合在一起的代码:
// Inside of tableView:cellForRowAtIndexPath:, after dequeueing the cell
cell.bounds = CGRect(x: 0, y: 0, width: CGRectGetWidth(tableView.bounds), height: 99999)
cell.contentView.bounds = cell.bounds
cell.layoutIfNeeded()
cell.nameLabel.preferredMaxLayoutWidth = CGRectGetWidth(cell.nameLabel.frame)
cell.idLabel.preferredMaxLayoutWidth = CGRectGetWidth(cell.idLabel.frame)
cell.actionsLabel.preferredMaxLayoutWidth = CGRectGetWidth(cell.actionsLabel.frame)
好吧,那我们在这里做什么?嗯,您会注意到添加了 3 行新代码。首先,我们需要设置此表视图单元格的宽度,使其与表视图的实际宽度相匹配(假设表视图已经布局并具有其最终宽度,这应该是这种情况)。我们实际上只是尽早使单元格宽度正确,因为表视图最终将执行此操作。
您还会注意到我们正在使用99999
对于高度。那是关于什么的?这是针对详细讨论的问题的简单解决方法here https://github.com/smileyborg/TableViewCellWithAutoLayout/issues/16,如果您的约束需要比单元格 contentView 的当前高度更多的垂直空间,您会得到一个约束异常,该异常实际上并不表示任何真正的问题。此时单元格或其任何子视图的高度实际上并不重要,因为我们只关心获取每个标签的最终宽度。
接下来,我们通过将 contentView 的边界设置为等于单元格的边界,确保单元格的 contentView 的大小与我们刚刚分配给单元格本身的大小相同。这是必要的,因为您创建的所有自动布局约束都是相对于 contentView 的,因此 contentView 必须具有正确的大小才能正确解决它们。只需手动设置单元格的大小即可not自动调整 contentView 的大小以匹配。
最后,我们在单元格上强制执行布局传递,这将使自动布局引擎解决您的约束并更新所有子视图的框架。由于单元格和内容视图现在具有与表视图中运行时相同的宽度,因此标签宽度也将是正确的,这意味着preferredMaxLayoutWidth
对每个标签的设置将是准确的,并将导致标签在正确的时间换行,这当然意味着当在表视图中使用单元格时,标签的高度将被正确设置!
这绝对是 Apple 在 UIKit 中的一个错误,我们现在必须解决这个问题(所以请这样做提交错误报告 https://bugreport.apple.com与 Apple 合作,因此他们优先修复!)。
最后一点:如果您的表视图单元格contentView
width 不会扩展表视图的整个宽度,例如当右侧显示部分索引时。在这种情况下,您需要确保在设置单元格的宽度时手动考虑到这一点 - 您可能需要对这些值进行硬编码,例如:
let cellWidth = CGRectGetWidth(tableView.bounds) - kTableViewSectionIndexWidth
cell.bounds = CGRect(x: 0, y: 0, width: cellWidth, height: 99999)