Slaknation
Slaknation

Reputation: 1926

Centering between two anchors

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

Answers (2)

Patrick
Patrick

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

matt
matt

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:

enter image description here

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

Related Questions