Reputation: 1926
I want to set a centerYAnchor
between two anchors. Similar to this:
centeredLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor),
However, I don't want it to be centered relative to the screen. I want it to be right in between two other anchors on the screen. Like if I have a toolbar at the top like this:
toolbar.topAnchor.constraint(equalTo: view.topAnchor),
Then I have a button at the bottom like this:
button.bottomAnchor.constraint(equalTo: guide.bottomAnchor, constant: -20)
is there a way I can center centeredLabel
's y constraint to be right between the bottomanchor of toolbar
and the top anchor of button
?
Upvotes: 2
Views: 1732
Reputation: 2412
Although @matt's solution works, here is a simpler one that uses autolayout without the need to create a UILayoutGuide.
iOS 10 introduced a simple way of doing this through NSLayoutXAxisAnchor.anchorWithOffset(to:)
and NSLayoutYAxisAnchor.anchorWithOffset(to:)
.
Here are convenience methods which wrap up this logic.
For X axis centering
extension NSLayoutXAxisAnchor {
func constraint(between anchor1: NSLayoutXAxisAnchor, and anchor2: NSLayoutXAxisAnchor) -> NSLayoutConstraint {
let anchor1Constraint = anchor1.anchorWithOffset(to: self)
let anchor2Constraint = anchorWithOffset(to: anchor2)
return anchor1Constraint.constraint(equalTo: anchor2Constraint)
}
}
For Y axis centering
extension NSLayoutYAxisAnchor {
func constraint(between anchor1: NSLayoutYAxisAnchor, and anchor2: NSLayoutYAxisAnchor) -> NSLayoutConstraint {
let anchor1Constraint = anchor1.anchorWithOffset(to: self)
let anchor2Constraint = anchorWithOffset(to: anchor2)
return anchor1Constraint.constraint(equalTo: anchor2Constraint)
}
}
To do what you need you can call:
centeredLabel.centerYAnchor.constraint(between: toolbar.bottomAnchor, and: button.topAnchor)
Upvotes: 3
Reputation: 535546
is there a way I can center centeredLabel's y constraint to be right between the bottomanchor of toolbar and the top anchor of button?
Yes, there is. The simple way is to use a transparent spacer view whose top is anchored to the upper anchor and whose bottom is anchored to the lower anchor. Now you center-anchor your label to the center of the spacer view.
However, although that is simple, it is not the best way. The best way is to create, instead of a transparent spacer view, a custom UILayoutGuide. Unfortunately this can be done only in code, not in the storyboard (whereas the spacer view and label can be configured entirely in the storyboard). But it has the advantage that it doesn't burden the rendering tree with an additional view.
Here's your situation, more or less, using a button as the upper view and a button as the lower view. The label is centered vertically between them:
Here's the code that generated that situation. b1
and b2
are the buttons (and it doesn't matter how they are created and positioned):
let g = UILayoutGuide()
self.view.addLayoutGuide(g)
g.topAnchor.constraint(equalTo: b1.bottomAnchor).isActive = true
g.bottomAnchor.constraint(equalTo: b2.topAnchor).isActive = true
g.leadingAnchor.constraint(equalTo:b1.leadingAnchor).isActive = true
g.trailingAnchor.constraint(equalTo:b1.trailingAnchor).isActive = true
let lab = UILabel()
lab.text = "Label"
lab.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(lab)
lab.leadingAnchor.constraint(equalTo:g.leadingAnchor).isActive = true
lab.centerYAnchor.constraint(equalTo:g.centerYAnchor).isActive = true
Upvotes: 7