我有以下单元格,其中包含以编程方式设置的约束:
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
方法只是添加约束的辅助方法。约束设置正确(Autolayout没有问题)。
然后在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
如果我将约束的设置移动到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
方法中设置约束......
感谢您的回答:)
修改我发现,当我在updateConstraints
中呼叫cell.updateConstraintsIfNeeded()
或cell.setNeedsUpdateConstraints()
时,它适用于cellForRowAtIndexPath
。为什么我们需要告诉单元格再次计算约束?在使用IB ...
答案 0 :(得分: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(){ ... }
内嵌入了约束设置。因此,在调用此函数时,您的约束已准备好应用。无需系统调用。