单元格中的破坏约束

Posted

技术标签:

【中文标题】单元格中的破坏约束【英文标题】:Broken constraints in the cell 【发布时间】:2018-05-19 16:30:32 【问题描述】:

我需要在我的单元格中显示一些 UIView,但是这个 UIView (backView) 的大小对于每个单元格是不同的。所以我也需要改变这个单元格的高度。

我正在尝试在运行时更改此backView 的高度和宽度,但我得到的只是一堆这样的自动布局错误:

[LayoutConstraints] 无法同时满足约束。将尝试通过打破约束来恢复...

我为这个单元格创建了 SimpleTextCell 类,它的 init 看起来像这样:

self.backView = UIView()
self.backView.translatesAutoresizingMaskIntoConstraints = false
self.backView.backgroundColor = UIColor.yellow
self.backView.layer.cornerRadius = 8.0
self.contentView.addSubview(backView)

let constraintBackViewTop = NSLayoutConstraint(item: backView, attribute: .top, relatedBy: .equal, toItem: contentView, attribute: .topMargin, multiplier: 1.0, constant: -5)
let constraintBackViewBottom = NSLayoutConstraint(item: backView, attribute: .bottom, relatedBy: .equal, toItem: contentView, attribute: .bottomMargin, multiplier: 1.0, constant: 5)
let constraintBackViewLeft = NSLayoutConstraint(item: backView, attribute: .left, relatedBy: .equal, toItem: contentView, attribute: .leftMargin, multiplier: 1.0, constant: 0)
constraintBackHeight = NSLayoutConstraint(item: backView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: superHeight)
constraintBackWidth = NSLayoutConstraint(item: backView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: superWidth)

self.contentView.addConstraints([constraintBackViewTop, constraintBackViewBottom, constraintBackViewLeft, constraintBackHeight, constraintBackWidth])

superHeightsuperWidth 只是这里的一些默认值。

我的cellForRowAt 函数是这样的:

let cell = tableView.dequeueReusableCell(withIdentifier: "simpleTextCell", for: indexPath) as! SimpleTextCell

cell.selectionStyle = .none
cell.backgroundColor = UIColor.red
cell.constraintBackHeight.constant = 100
cell.constraintBackWidth.constant = 200
cell.updateConstraints()

而且它根本不起作用。我有错误(就像我之前提到的那样),虽然我的单元格的高度有点正确,但我的backView 是不可见的,因为backView.frame 的宽度为零(我不知道为什么) backView 的高度为 100(相同)。看来我的新约束被忽略了。

我尝试在cellForRowAt 中为这些约束设置优先级:

cell.constraintBackHeight.priority = UILayoutPriority.init(rawValue: 999)

结果是运行时错误。

我尝试通过以下方式克服此错误:

cell.constraintBackHeight.isActive = false
cell.constraintBackHeight.priority = UILayoutPriority.init(rawValue: 999)
cell.constraintBackHeight.isActive = true

但它也不起作用。

我该如何解决这个问题?

【问题讨论】:

为什么不制作一个自定义单元格来调整其内容的大小?您在数据源本身中设置和更新约束的方法是个坏主意。 这个 backView 实际上相当复杂,因为它包含几个 UILabel(我事先不知道它们的数量或大小,所以我无法在单元类中为它们创建约束)。所以我必须在 cellForRowAt 中计算容器的高度(backView)并更新容器的约束(高度和宽度)。我有一种感觉,这不是一个最佳解决方案,但现在它是我能想到的最好的解决方案。如果你有另一个,我会很高兴听到这个消息,谢谢。 首先,您不需要制作一个万能的单元格,尤其是当它在运行时被观察者和约束更改污染时。不要害怕制作多个满足不同配置的单元格,并在数据源中将正确的单元格出列。数据源应该尽可能精简,因为它被大量调用并且膨胀它会影响性能并消耗内存。如果必须,请考虑组合标签。但是,当您将单元格的子视图锚定到单元格的边缘时,单元格会自动调整大小。所以想出一个聪明的方法来使这项工作对你有利。 是的,我知道。我在此表中使用了几个自定义单元格,但我相信如果我为具有 2 个 UILabel、3 个 UILabel 等的单元格创建不同的类,那就太多了(不幸的是,我不想组合这些标签)。有问题的单元格是自定尺寸的,我遇到的问题是关于内部视图,它决定了单元格的高度,但可能比单元格窄。无论如何,谢谢,我会再考虑一下这个解决方案。 【参考方案1】:

问题来了

 constraintBackHeight = NSLayoutConstraint(item: backView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: superHeight)
 constraintBackWidth = NSLayoutConstraint(item: backView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: superWidth)

您设置了 2 个高度限制,可能是您刚刚复制为宽度而忘记将其更改为 .width

【讨论】:

谢谢,你救了我。我仍然遇到自动布局错误,但它有效!

以上是关于单元格中的破坏约束的主要内容,如果未能解决你的问题,请参考以下文章

如何为自定义单元格中的动态附加输入字段添加约束

以编程方式约束表格单元格中的 UILabel

如何使用 UIImageView 和单元格中的多个标签正确地进行约束?

iOS:如何在代码中的表格单元格中为文本字段添加约束

在 calendarTableView 自定义单元格中添加视图破坏了代码 Swift 4

UIImageView 适合自调整大小的 tableview 单元格中的最大宽度