0

I'm a little late to the Auto Layout party, but I've been trying for a couple of days to understand why some of my animated constraint changes don't always work, nor do they produce any errors in the console.

Essentially, I have:

  • Two containers (top: red, bottom: orange)
  • A child view label (yellow - the one which says "Hello!") in the bottom view (orange)

As you can see from the GIF, adjusting the height of the top (red) view causes the orange container to grow... which in turn also causes the yellow view to stretch with it. However, when the red view becomes smaller, I get some weird behaviour with the yellow view immediately shrinking down to size, rather than following the animation of the orange view.

Unusual closing animation

My constraints are configured as follows:

topViewHeightConstraint = topView.heightAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.heightAnchor, multiplier: 0.7)
NSLayoutConstraint.activate([
  // Setup the top view
  topView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor),
  topView.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor),
  topView.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor),
  topViewHeightConstraint!,

  // Setup the constraits for the button inside the top view
  topViewButton.centerXAnchor.constraint(equalTo: topView.centerXAnchor),
  topViewButton.bottomAnchor.constraint(equalTo: topView.bottomAnchor, constant: -20),
  topViewButton.widthAnchor.constraint(equalToConstant: 100),
  topViewButton.heightAnchor.constraint(equalTo: topViewButton.widthAnchor, multiplier: 1.0),

  // Setup the bottom view
  bottomView.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor),
  bottomView.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor),
  bottomView.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor),
  bottomView.topAnchor.constraint(equalTo: topView.bottomAnchor),

  // Setup constraints for the label
  labelInsideBottomView.bottomAnchor.constraint(equalTo: self.bottomView.bottomAnchor),
  labelInsideBottomView.leadingAnchor.constraint(equalTo: self.bottomView.leadingAnchor),
  labelInsideBottomView.trailingAnchor.constraint(equalTo: self.bottomView.trailingAnchor),
  labelInsideBottomView.widthAnchor.constraint(equalTo: self.bottomView.widthAnchor),
  labelInsideBottomView.heightAnchor.constraint(equalTo: self.bottomView.heightAnchor)
])

Then, to resize the container view I'm calling the following code (with help of an extension to replace a multiplier constraint), I'm updating the constraint.

func moveViews() {
    if (topViewHeightConstraint.multiplier >= 0.69) {
        topViewHeightConstraint = topViewHeightConstraint.setMultiplier(multiplier: 0.5)
    } else {
        topViewHeightConstraint = topViewHeightConstraint.setMultiplier(multiplier: 0.7)
    }

    UIView.animate(withDuration: 1) {
        self.view.layoutIfNeeded()
    }
}

Can anyone see anything unusual about my setup, or suggest a way I can achieve this without the weird animation?

Thanks!

Jamie Chapman
  • 4,229
  • 5
  • 29
  • 47
  • 1
    Instead of animating the change of constraints, try removing the constraints, animating frames, and restoring constraints. – matt Sep 15 '18 at 13:47
  • Thanks for the tip @matt, I'll give that a shot! – Jamie Chapman Sep 15 '18 at 13:53
  • BTW frame animation for topView won't update other parts , you may encounter a bug test on real device if this is a simulator or try other device – Shehata Gamal Sep 15 '18 at 13:56
  • @matt it's unclear what you mean. Do you mean that he should not be using constraints at all and just use frames? If so then why did you say 'and restoring constraints' at the end? – mfaani Sep 15 '18 at 15:09
  • 1
    This problem with animating label size has been observed [before](https://stackoverflow.com/q/26595513/1630618). As a workaround, you could put your label in its own containing view such that the label background itself wouldn't have to resize or animate. Just use two constraints within that view to position the label (eg. center it vertically, constrain its leading edge) and let the intrinsic size of the label set the width and height. Then use the same constraints to place this containing view as you used for the label before. – vacawama Sep 15 '18 at 15:20

0 Answers0