Why is layoutIfNeeded() not animating navigationBar's BarButtonItem?

63 Views Asked by At

I am trying to make a simple e-commerce app with a dynamic barButton to show users their total cart cost. I wanted to add an animation to it. So that the button needs to collapse and expand whenever its value changes. I used layoutIfNeeded() method after updating button's constraints. However the animation is not working. The code is a bit complex so I am sharing a code sample and a video to give you a rough idea what I have done so far. What could be changed to get desired animation?

Gif

cartBarButton


Code

class ProductsViewController: UIViewController {

  ...
  var cartBarButton: UIBarButtonItem!
  var cartBarButtonWidthConstraint: NSLayoutConstraint?
  var price: Double = 0
  ...

  override func viewDidLoad() {
    super.viewDidLoad()

    configureCartButton()
    ...
  }

  func configureCartButton() {

    let cartButton = CustomCartButton(color: color, image: image, title: price.currencyString)

    cartButton.addTarget(self, action: #selector(updateCartCost), for: .touchUpInside)
        
    cartBarButton = UIBarButtonItem(customView: cartButton)
    cartBarButton.customView?.translatesAutoresizingMaskIntoConstraints = false
        
    cartBarButtonWidthConstraint = cartBarButton.expand(considering: price) // expand() method is extension to UIBarButtonItem, returns barButton's widthAnchor constraint
    cartBarButtonWidthConstraint?.isActive = true
        
    navigationItem.rightBarButtonItem = cartBarButton

  }

  @objc private func updateCartCost() {
    
    cartBarButtonWidthConstraint?.isActive = false
    cartBarButtonWidthConstraint = cartBarButton.collapse(to: 25) // collapse() method is an extension to UIBarButtonItem
    cartBarButtonWidthConstraint?.isActive = true
    UIView.animate(withDuration: 1) {
      self.view.layoutIfNeeded()
    }

    price += 90
    cartBarButtonWidthConstraint?.isActive = false
    cartBarButtonWidthConstraint = cartBarButton.expand(considering: price)
    cartBarButtonWidthConstraint?.isActive = true
    UIView.animate(withDuration: 1) {
      self.view.layoutIfNeeded()
    }
    self.cartButton.title = self.price.currencyString
  }

}
1

There are 1 best solutions below

1
HangarRash On

You are changing the constraint to collapse and the constraint to expand at the same time and doing both animations at the same time.

You should move all of the code to do the expansion in the completion handler of the collapse animation. This should allow the two changes to happen one after the other instead being all done at once.

Something like this (not verified it will compile but it gives you the idea):

@objc private func updateCartCost() {
    cartBarButtonWidthConstraint?.isActive = false
    cartBarButtonWidthConstraint = cartBarButton.collapse(to: 25) // collapse() method is an extension to UIBarButtonItem
    cartBarButtonWidthConstraint?.isActive = true
    UIView.animate(withDuration: 1, animations: {
      self.view.layoutIfNeeded()
    }) { finished in
        price += 90
        cartBarButtonWidthConstraint?.isActive = false
        cartBarButtonWidthConstraint = cartBarButton.expand(considering: price)
        cartBarButtonWidthConstraint?.isActive = true
        UIView.animate(withDuration: 1) {
             self.view.layoutIfNeeded()
        }
    }

    self.cartButton.title = self.price.currencyString
}