TimSim TimSim - 7 months ago 23
Swift Question

Adding, reusing and removing NSLayoutAnchors

So I have a container view (that is docked to the edges of the screen) and a child view that's supposed to slide in and out of it.

func slideOut() {
UIView.animateWithDuration(Double(0.5), animations: {
self.container.bottomAnchor
.constraintEqualToAnchor(self.child.bottomAnchor).active = false
self.view.layoutIfNeeded()
})
}

func slideIn() {
UIView.animateWithDuration(Double(0.5), animations: {
self.container.bottomAnchor
.constraintEqualToAnchor(self.child.bottomAnchor).active = true
self.view.layoutIfNeeded()
})
print("numConstraints: \(container.constraints.count)")
}


The
slideIn()
animation is fine, just as it's supposed to be. The problem is I don't know how to do the
slideOut()
animation. If I just deactivate the
NSLayoutConstraint
like above, then nothing happens. If instead I try:

self.container.bottomAnchor
.constraintEqualToAnchor(self.child.topAnchor).active = true


then there is a warning about being unable to simultaneously satisfy constraints and nothing happens visually.
Also, whenever I make a
NSLayoutConstraint
active, the number of constraints (
print(container.constraints.count)
) increases, which can't be a good thing.

So my questions are:


  1. How do I do a reverse of the
    slideIn()
    animation in this case?

  2. How do I reuse the existing constraints in case of repeated animations so that the number of constraints doesn't add up?


Answer

The constraintEqualToAnchor method creates a new constraint. So when you're calling self.container.bottomAnchor.constraintEqualToAnchor(self.child.bottomAnchor) in the slide-out function you're not using the constraint you added in the slideIn method.

To achieve the desired slide-out animation you would have to keep a reference to the previous constraint. I'm not sure what the effect of setting the .active property on the constraint would be in the slide-out function since I don't know how your view hierarchy is set up. But one way of reusing the constraint would be holding it as a var property in your VC:

lazy var bottomConstraint:NSLayoutConstraint = self.container.bottomAnchor
        .constraintEqualToAnchor(self.child.bottomAnchor)

func slideOut() {
    UIView.animateWithDuration(Double(0.5), animations: {
        self.bottomConstraint.active = false
        self.view.layoutIfNeeded()
    })
}

func slideIn() {
    UIView.animateWithDuration(Double(0.5), animations: {
        self.bottomConstraint.active = true
        self.view.layoutIfNeeded()
    })
    print("numConstraints: \(container.constraints.count)")
}

From Apple Docs:

Activating or deactivating the constraint calls addConstraint: and removeConstraint: on the view that is the closest common ancestor of the items managed by this constraint.

So the reason why you're seing the increased number of constraints is because you keep creating new ones and adding them by setting active to true.

Comments