为啥 UITableView 滚动时会更新约束?
Posted
技术标签:
【中文标题】为啥 UITableView 滚动时会更新约束?【英文标题】:Why constraints are updated on scrolling of UITableView?为什么 UITableView 滚动时会更新约束? 【发布时间】:2018-12-28 14:54:40 【问题描述】:我有 2 个简单的 UILabel 需要水平放置。其中一个在视图的右侧,而第二个在左侧并获得所有可能的空间。这是我的限制:
amountOfQuestions.rightAnchor.constraint(equalTo: rightAnchor, constant: -8).isActive = true
amountOfQuestions.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
topicName.leftAnchor.constraint(equalTo: leftAnchor, constant: 8).isActive = true
topicName.topAnchor.constraint(equalTo: topAnchor, constant: 8).isActive = true
topicName.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -8).isActive = true
topicName.rightAnchor.constraint(equalTo: amountOfQuestions.leftAnchor, constant: -8).isActive = true
看起来一切正常,但是当显示表格视图时,它看起来像这样:
但是在我上下滚动我的表格几次后,它就变得正常了:
为什么我的表格没有像第二张图片那样立即显示?
解决办法:
amountOfQuestions.rightAnchor.constraint(equalTo: rightAnchor, constant: -8).isActive = true
amountOfQuestions.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
amountOfQuestions.setContentHuggingPriority(.required, for: .horizontal)
amountOfQuestions.setContentCompressionResistancePriority(.required, for: .horizontal)
topicName.leftAnchor.constraint(equalTo: leftAnchor, constant: 8).isActive = true
topicName.topAnchor.constraint(equalTo: topAnchor, constant: 8).isActive = true
topicName.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -8).isActive = true
topicName.rightAnchor.constraint(equalTo: amountOfQuestions.leftAnchor, constant: -8).isActive = true
topicName.setContentHuggingPriority(.required, for: .horizontal)
topicName.setContentCompressionResistancePriority(.required, for: .vertical)
let myBottom = topicName.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -8)
myBottom.priority = UILayoutPriority(rawValue: UILayoutPriority.required.rawValue - 1)
myBottom.isActive = true
【问题讨论】:
你在哪里设置约束?另请注意,底部约束应将优先级设置为999
(不是必需但高优先级),并且您需要将左侧标签上的垂直拥抱优先级和抗压优先级设置为1000(必需)。并且您必须为正确的标签设置水平拥抱优先级和抗压性。如果你不这样做,那么标签内容将不会被正确考虑。
谢谢。我有问题地展示了我是如何设置约束的。但是,为什么需要你告诉的那些限制?他们如何解决问题?为什么不使用它们就无法实现目标?
【参考方案1】:
有多个问题会影响布局并使其定义不正确:
永远不要将内容限制在单元格本身。始终限制为单元格的contentView
,例如:
amountOfQuestions.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -8).isActive = true
(确保将标签添加为 contentView
的子视图,而不是单元格本身的子视图)。
如果您希望标签的大小产生任何影响,则需要正确设置拥抱和抗压优先级。否则布局不必尊重内容:
// you want topic name to resize vertically to respect the content
topicName.setHuggingPriority(.required, for: .vertical)
topicName.setContentCompressionResistancePriority(.required, for: .vertical)
// you want amount of question to resize horizontally to respect the content
amountOfQuestions.setHuggingPriority(.required, for: .horizontal)
amountOfQuestions.setContentCompressionResistancePriority(.required, for: .horizontal)
为避免在第一次布局期间出现布局冲突,最好将其中一个垂直约束设置为稍低的布局优先级:
let bottomAnchor = topicName.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -8)
bottomAnchor.priority = UILayoutPriority(rawValue: UILayoutPriority.required.rawValue - 1)
bottomAnchor.isActive = true
【讨论】:
您对 contentView 的第一个建议失败了。没有 contentView 工作,有了它,它就不起作用。 @abay 描述“不起作用”。您是否使用contentView.addSubview(topicName)
将标签添加到contentView
?
我有罪。对不起。但是你能澄清一下为什么需要使用 contentView 吗?它有什么好处?
@abay 好吧,内容视图不必与单元格本身具有相同的大小。将配件添加到单元格时,您可以看到差异。然后contentView
变小,如果您将内容限制在单元格本身,它将与附件冲突。在编辑模式(例如单元格删除按钮)或滑动操作中会出现类似问题。【参考方案2】:
1- UILabel 有一个内在的内容值,这意味着你不必为它们指定宽度/高度,所以当你像这样水平放置它们时
| - lbl1 - lbl2 - |
这会导致约束模糊,因为当一个内容太大时,自动布局需要知道要修剪哪个标签,这就是为什么您需要将水平压缩阻力 && setHuggingPriority 设置为 lbl2 = 1000
2- 您需要降低底部约束的优先级,因为单元格在布局开始时假定固定高度,并且该高度可能与垂直内容的当前总高度冲突,因此您降低它以避免这种冲突
【讨论】:
以上是关于为啥 UITableView 滚动时会更新约束?的主要内容,如果未能解决你的问题,请参考以下文章
当 SuperViews 约束改变时更新 SubView 约束
为啥滚动 UITableView 比滚动 UIScrollView 响应更快?