未计算 UITableViewCell 中的约束
Posted
技术标签:
【中文标题】未计算 UITableViewCell 中的约束【英文标题】:Constraints in UITableViewCell not being calculated 【发布时间】:2018-03-28 06:58:24 【问题描述】:我有以下单元格以编程方式设置约束:
class RadioButtonCell: UITableViewCell
static let identifier = "RadioButtonCell"
let radioButton = RadioButton()
let labelTitle = UILabel()
private var didUpdateConstraints = false
override init(style: UITableViewCellStyle, reuseIdentifier: String?)
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupSubViews()
required init?(coder aDecoder: NSCoder)
fatalError("init(coder:) has not been implemented")
private func setupSubViews()
radioButton.translatesAutoresizingMaskIntoConstraints = false
labelTitle.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(radioButton)
contentView.addSubview(labelTitle)
override func updateConstraints()
super.updateConstraints()
if !didUpdateConstraints
radioButton.anchor(leading: contentView.leadingAnchor, padding: UIEdgeInsets(top: 0, left: Constants.UI.defaultMarginX2, bottom: 0, right: 0))
radioButton.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true
labelTitle.anchor(leading: radioButton.trailingAnchor, padding: UIEdgeInsets(top: 0, left: Constants.UI.defaultMarginX2, bottom: 0, right: 0))
labelTitle.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true
didUpdateConstraints = true
anchor
方法只是添加约束的辅助方法。约束设置正确(自动布局没有问题)。
然后在cellForRowAtIndexPath
方法中创建单元格,如下所示:
guard let cell = tableView.dequeueReusableCell(withIdentifier: RadioButtonCell.identifier, for: indexPath) as? RadioButtonCell else return UITableViewCell()
radtioButtonController.addButton(cell.radioButton)
cell.labelTitle.text = "test"
return cell
这在 tableView 中创建了以下布局(这显然是错误的):
如果我将约束的设置移动到setupSubViews()
方法,则布局是正确的:
class RadioButtonCell: UITableViewCell
static let identifier = "RadioButtonCell"
let radioButton = RadioButton()
let labelTitle = UILabel()
private var didUpdateConstraints = false
override init(style: UITableViewCellStyle, reuseIdentifier: String?)
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupSubViews()
required init?(coder aDecoder: NSCoder)
fatalError("init(coder:) has not been implemented")
private func setupSubViews()
radioButton.translatesAutoresizingMaskIntoConstraints = false
labelTitle.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(radioButton)
contentView.addSubview(labelTitle)
radioButton.anchor(leading: contentView.leadingAnchor, padding: UIEdgeInsets(top: 0, left: Constants.UI.defaultMarginX2, bottom: 0, right: 0))
radioButton.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true
labelTitle.anchor(leading: radioButton.trailingAnchor, padding: UIEdgeInsets(top: 0, left: Constants.UI.defaultMarginX2, bottom: 0, right: 0))
labelTitle.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true
为什么会这样?我认为我们应该在updateConstraints
方法中设置约束...
谢谢你的回答:)
编辑我发现,当我在cellForRowAtIndexPath
中调用cell.updateConstraintsIfNeeded()
或cell.setNeedsUpdateConstraints()
时,它适用于updateConstraints
。为什么我们需要告诉单元格再次计算约束?使用 IB 添加约束时,我们不需要这样做...
【问题讨论】:
【参考方案1】:嗯,在您的第一个示例中,您不只是将约束添加到 init
中的 UI 元素。您只需设置子视图。
override init(style: UITableViewCellStyle, reuseIdentifier: String?)
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupSubViews()
// No explicit constraint setup happened
要设置约束,您已经覆盖了override func updateConstraints() ...
方法。我们来看看official documentation from Apple。
简而言之,当您通知系统您需要更新约束时,您的覆盖将生效。因此,您需要通过调用
setNeedsUpdateConstraints()
或updateConstraintsIfNeeded()
来明确通知系统。
让我们看看你的第二个例子。您在 private func setupSubViews() ...
中嵌入了约束设置。因此,在调用此函数时,您的约束已准备好应用。无需系统调用。
【讨论】:
好的,谢谢!后续问题:在 updateConstraints() 中设置约束时,我遇到了不需要显式调用 setNeedsUpdateConstraints() 或 updateConstraintsIfNeeded() 的视图。在什么情况下会发生这种情况? 好的,如果您遇到这种情况,那么不知何故,setNeedsUpdateConstraints()
或 updateConstraintsIfNeeded()
中的任何一个都会被调用。通常这是通过setup...
方法完成的,例如self.setNeedsUpdateConstraints()
。以上是关于未计算 UITableViewCell 中的约束的主要内容,如果未能解决你的问题,请参考以下文章
UITextView 高度未在 UITableViewCell 中调整大小