0

I setup an animation to hide one switch/label when another one is turned on. Simultaneously the switch that was just turned on move up. This works great with the simple explanation here.

However, when I try to move the switch/label back down after it is turned off it doesn't budge. The other switch reappears fine, but the top constraint change doesn't fire.

I'm relatively new to doing this type of setup and animating all programmatically and after spending an hour on this I'm stumped. Is it because I'm animating a top constraint relative to another one? How does that matter if it works the first time around? Even though the alpha of the hidden switch is set to zero, its frame is still there, right? Or am I doing something simple stupidly?

// Works Perfectly!

func hideVeg() {

    self.view.layoutIfNeeded()

    UIView.animate(withDuration: 1, delay: 0, options: [.curveEaseIn], animations: {
        self.vegetarianSwitch.alpha = 0
        self.vegetarianLabel.alpha = 0
        self.veganSwitch.topAnchor.constraint(equalTo: self.vegetarianSwitch.bottomAnchor, constant: -30).isActive = true
        self.view.layoutIfNeeded()
    })
}

// Showing the label and switch works, but the topAnchor constraint never changes!

func showVeg() {

    self.view.layoutIfNeeded()

    UIView.animate(withDuration: 1, delay: 0, options: [.curveEaseIn], animations: {
        self.vegetarianSwitch.alpha = 1
        self.vegetarianLabel.alpha = 1

        // This is the constraint that doesn't change.
        // This is exactly what it was set to before the other hideVeg() runs.
        self.veganSwitch.topAnchor.constraint(equalTo: self.vegetarianSwitch.bottomAnchor, constant: 40).isActive = true
        self.view.layoutIfNeeded()
    })
}
Ben
  • 3,346
  • 6
  • 32
  • 51

2 Answers2

0

The issue here is that you are not modifying the constraints but actually creating new constraints with each animation. What you want to do instead is just create the constraint once (you can do it in code or in Interface Builder and drag and outlet). You can then just change the .constant field of the existing constraint in your animation block.

Josh Homann
  • 15,933
  • 3
  • 30
  • 33
  • Thanks for the idea! I'm setting this up all programmatically, so no constraint to modify from IB. You've given me a new avenue to explore to figure this out though. I feel like I could fall back on creating a height constraint and modifying that, but it creates other complications, so I'm trying to avoid that approach. It feels like there's a simple fix here that I'm just not seeing. – Ben Mar 12 '19 at 21:44
  • Yes you should make the height constraint in code and keep it around. If not you need to go through all of the constraints and remove the height constraint before adding a new one, which is much more work. – Josh Homann Mar 12 '19 at 21:46
  • I figured out how to do it without resorting to the height anchor approach. You pointed me in the right direction that got me there. I posted the code, so if you want to edit your answer I will accept it as the correct one. Thanks! – Ben Mar 12 '19 at 23:22
0

The constant needs to be changed with the animation, not creating an entirely new constraint. The old constraint still exists causing the issue.

var veganTopConstraint = NSLayoutConstraint()

// Top Constraint set up this way so it can be animated later.
veganTopConstraint = veganSwitch.topAnchor.constraint(equalTo: vegetarianSwitch.bottomAnchor, constant: 40)
veganTopConstraint.isActive = true


func hideVeg() {

    UIView.animate(withDuration: 1, delay: 0, options: [.curveEaseIn], animations: {
        self.vegetarianSwitch.alpha = 0
        self.vegetarianLabel.alpha = 0

        self.veganTopConstraint.constant = -30

        self.view.layoutIfNeeded()
    })
}

func showVeg() {

    self.view.layoutIfNeeded()

    UIView.animate(withDuration: 1, delay: 0, options: [.curveEaseIn], animations: {
        self.vegetarianSwitch.alpha = 1
        self.vegetarianLabel.alpha = 1

        self.veganTopConstraint.constant = 40

        self.view.layoutIfNeeded()
    })
}
Ben
  • 3,346
  • 6
  • 32
  • 51