Reputation: 727
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!
Upvotes: 0
Views: 933
Reputation: 47
This question is pretty old but I am also following too Paul Hudsons' Hacking with Swift tutorials and I have difficulties in Project 6 about same issue. But I figured out and it might be helpful to any other person.
For trailing and bottom constraints, value should be negative both view.safeAreaLayoutGuide.bottomAnchor and view.trailingAnchor. As far as I understand, dimension is determined always to rightward and downward.
label5.bottomAnchor.constraint(greaterThanOrEqualTo: view.safeAreaLayoutGuide.bottomAnchor, constant: 10.0).isActive = true
With this code, chopping off is pretty normal because by entering a positive value (+10.0), you already initialize the contsraint in the way that your label5's bottomAnchor will be under the safeAreaLayoutGuide bottomAnchor's by 10 units.
So, why does label5 seem in the view, entirely? Because label1 is attached to safeAreaLayoutGuide, your labels have determined vertical space between each other. Probably when you run the code, XCode will show some error and ignore some constraint. You may try to not determine a specific height. You can use:
label1.heightAnchor.constraint(greaterThanOrEqualToConstant: 80).isActive = true
And for the safeAreaLayoutGuide:
label5.bottomAnchor.constraint(lessThanOrEqualTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -10.0).isActive = true
Upvotes: 0
Reputation: 966
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
:
Upvotes: 1