I've been following Paul Hudsons' Hacking with Swift tutorials and I'm up to project 6 where he uses layout constraint programmatically. I've been doing this kind of task solely using Interface Builder, but I'm keen to learn on how to do it programmatically.
From his tutorial, we have the following code that add 5 UILabels to the main controller's view.
let label1 = UILabel()
label1.translatesAutoresizingMaskIntoConstraints = false
label1.text = "THESE"
label1.backgroundColor = #colorLiteral(red: 0.5725490451, green: 0, blue: 0.2313725501, alpha: 1)
label1.sizeToFit()
// do the same with label2, label3, label4, label5
view.addSubview(label1)
view.addSubview(label2)
view.addSubview(label3)
view.addSubview(label4)
view.addSubview(label5)
and then I can add constraints manually:
let dictionary = [
"label1": label1,
"label2": label2,
"label3": label3,
"label4": label4,
"label5": label5
]
let metrics=[ "labelHeight":80]
view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[label1(labelHeight@999)]-[label2(label1)]-[label3(label1)]-[label4(label1)]-[label5(label1)]-(>=10)-|", options: [], metrics: metrics, views: dictionary))
for label in dictionary.keys {
view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[\(label)]|", options: [], metrics:nil, views: dictionary))
}
as you can see, I'm setting the first label's height to be 80. Then set label1 to have priority of 999, and make the remaining labels to follow label1's height constraint.
This is working fine, both in portrait and landscape mode.
Now i'm converting the code to use anchor.
let heightConstraint = label1.heightAnchor.constraint(equalToConstant: 88)
heightConstraint.priority = UILayoutPriority(rawValue: 999)
heightConstraint.isActive = true
for label in [label2, label3, label4, label5] {
label.heightAnchor.constraint(equalTo: label1.heightAnchor, multiplier: 1).isActive = true
}
var previousLabel : UILabel?
for label in [label1, label2, label3, label4, label5] {
label.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 0).isActive = true
label.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: 0).isActive = true
if let previousLabel = previousLabel {
label.topAnchor.constraint(equalTo: previousLabel.bottomAnchor, constant: 10).isActive = true
} else {
label.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 0).isActive = true
}
previousLabel = label
}
label5.bottomAnchor.constraint(greaterThanOrEqualTo: view.safeAreaLayoutGuide.bottomAnchor, constant: 10.0).isActive = true
I think I'm missing something here, because
I think i'm missing something here when using anchor? I'm guessing it is this bit:
-(>=10)-
But i'm not sure how to do it with anchor mode. Any assistance would be greatly appreciated!
For label5 you should change a bottom constraint to:
label5.bottomAnchor.constraint(lessThanOrEqualTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -10.0).isActive = true
It should be a negative number since you fix it to the anchor, which is below (in contrast to previous anchors where you fix it to the label above your current one). And for negative numbers you need to use lessThanOrEqualTo
.
For the vertical layout it works fine too since constraint is lessThanOrEqualTo
: