如何修复似乎不影响自定义 UITableViewCell 布局的奇怪 NSLayoutConstraint 错误

Posted

技术标签:

【中文标题】如何修复似乎不影响自定义 UITableViewCell 布局的奇怪 NSLayoutConstraint 错误【英文标题】:How to fix strange NSLayoutConstraint errors that don't seem to effect layout in custom UITableViewCell 【发布时间】:2013-11-10 01:57:45 【问题描述】:

每次我的自定义 UITableViewCells 由 tableView:cellForRowAtIndexPath 绘制时:控制台会吐出一堆 NSLayoutConstraint 不一致。我了解其中的大部分内容:

 Unable to simultaneously satisfy constraints. ...boring stuff..

 "<NSLayoutConstraint:0x8b0eb60 V:|-(NSSpace(20))-[UILabel:0x8b0cb30]   (Names: '|':UITableViewCellContentView:0x8bd7d40 )>",
"<NSLayoutConstraint:0x8b0db70 V:[UILabel:0x8b0cb30]-(NSSpace(8))-[UITextView:0x91dba00]>",
"<NSLayoutConstraint:0x8b0dba0 V:[UITextView:0x91dba00]-(NSSpace(20))-|   (Names: '|':UITableViewCellContentView:0x8bd7d40 )>",
"<NSLayoutConstraint:0x8b0d5a0 V:[UITextView:0x91dba00(1000)]>",
"<NSAutoresizingMaskLayoutConstraint:0x8b00330 h=--& v=--& V:[UITableViewCellContentView:0x8bd7d40(44)]>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x8b0db70 V:[UILabel:0x8b0cb30]-(NSSpace(8))-[UITextView:0x91dba00]>

或者至少我认为是的。真正让我感到困惑的是,我的 UITableViewCell 正在工作,并且似乎没有任何约束被打破。我认为错误中列出的一些约束,特别是最后一个,是系统添加的约束。如果我不使用 .xibs 并且只在代码中添加了约束,这可能吗?错误中的最后一行对我来说特别突出,因为我正在为每个代码动态生成高度,但我注意到其中的 44,即默认单元格高度。

是否默认添加了其中一些约束,例如当我调用[super updateConstraints] 时?我将如何解决这些错误或找出它们的来源?

顺便说一句,我知道使用 Core Text 比我的 UITextView + Auto Layout 解决方案要好得多。现在我正在研究缓存单元高度。但是,这些布局错误是否会导致滚动时出现延迟,或者仅仅是因为我使用自动布局来计算屏幕上出现的每个单元格高度?

如果有人想下载并亲自体验这种怪异,我已经发布了the project in which these errors are occurring on Github。

【问题讨论】:

当你的 UITableViewCell 的高度是 44 时,这些约束不能全部满足,这是它的默认高度。您可以通过手动指定大于20 + 8 + 20 + 1000 + your label's intrinsic content size height 的默认高度来消除这些错误。或者,如果您在手动计算身高后看不到它们,则可以忽略它们。 顺便说一句,您可能希望避免在 UITableViewCell 中使用自动布局,因为它是滚动性能不佳(不稳定)的常见原因。 @AaronBrager 我让它工作了,但是在 initWithStyle: 和 prepareForReuse: 中将单元格的 contentView.frame.height 设置为一个大常数。感谢您的帮助! 【参考方案1】:

根据 Aaron 的建议,我在初始化时手动更改单元格的高度,以便在自动布局进行计算时约束可以控制它。最初没有设置内容框架,默认框架是0, 0, 320, 44。这太小了,无法满足控制台中显示的约束和错误。

类似地,当重用单元格时,旧的 contentView.frame(由自动布局计算)仍然存在。如果您使用相同数量的文本(或更少),这很好,但如果新单元格需要更多文本(因此需要更大的 contentView.frame),我们会遇到同样的问题,contentView.frame 太小并且不能满足约束。

所以,在我的自定义 UITableViewCell 中,我现在手动将 initWithStyle:prepareForReuse: 中的 contentView.frame.height 设置为一个足够大的常量,以容纳任意数量的文本(足以容纳 App.net 帖子和一些额外的空间)。这样可以确保 Auto Layout 进行计算时不会出错。

我什至可能会考虑将这个值设置得更高一点,甚至动态地设置,以适应 ios 7 中的动态文本。至于滚动,似乎错误并没有加剧不稳定的滚动,这都是因为自动布局计算(我认为)。下一步是在调用viewDidAppear: 时计算单元格高度...

【讨论】:

"下一步是在调用viewDidAppear: 时计算单元格高度..." ...您可能希望在数据(文本)从服务器到达时计算单元格高度,并存储结果。然后,当您需要显示单元格时,您不需要进行任何计算。 我想出了一种计算单元格高度减去 UITextView 高度的方法,所以在 heightForRowAtIndexPath 中我只计算 UITextView 所需的高度。滚动很流畅,我什至不需要实现缓存。我曾考虑在数据到达时进行计算,但现在我在没有完整的模型对象的情况下工作,只是本地和随机生成的内容。不过我会记住的。此外,我的解决方案现已在 Github 上发布。 我可以确认在 initWithStyle: 和 prepareForReuse: 中设置 contentView 高度是一个很好的解决方案。可能希望将此答案标记为已接受,即使它是您自己对自己问题的回答。 @Simone 我会这样做的。我忘记了这个问题,因为我在调用 reloadData 之前切换到手动预先计算单元格高度。 AutoLayout 很好,但是在处理滚动许多单元格时,事情很容易变慢。可悲的是,我已切换到手动设置框架。 如果您应用正确的约束,单元格将根据 UITableView.RowHeight 自动调整大小或覆盖 GetHeightForRow 方法

以上是关于如何修复似乎不影响自定义 UITableViewCell 布局的奇怪 NSLayoutConstraint 错误的主要内容,如果未能解决你的问题,请参考以下文章

如何修复此 WordPress 功能使其不返回 404 页面?

将一个水龙头从 UIScrollView 传递到其父视图

故事板中的自定义转场

如何修复自定义模块中的“未定义变量”

如何修复自定义按钮在 SwiftUI(IOS) 中的交互?

如何修复错误 [Vue 警告]:未知的自定义元素?