Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?
like image 382
TimSim Avatar asked May 01 '16 21:05

TimSim


1 Answers

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.

like image 131
marosoaie Avatar answered Oct 12 '22 11:10

marosoaie