Stefan
Stefan

Reputation: 936

UIView Animation not working with NSLayoutConstraint?

I have a keyboard notification and I want it so that when it goes off, the placeholder view animates to the left edge of the search bar.

Below is what I use to call the animation which is asynchronous with the keyboard opening. Currently, the view moves to the spot I want it to, however it's as if it's teleporting there rather than animating.

        DispatchQueue.main.async {
            if isKeyboardShowing {
                UIView.animate(withDuration: 2, delay: 1, options: UIViewAnimationOptions.curveEaseOut, animations: {
                    NSLayoutConstraint(item: self.placeholder, attribute: .left, relatedBy: .equal, toItem: self.searchBar, attribute: .left, multiplier: 1, constant: 5).isActive = true
                }, completion: { (completed) in

                })

            }
        }

Any Suggestions?

Upvotes: 2

Views: 1514

Answers (2)

Aleksandr Medvedev
Aleksandr Medvedev

Reputation: 8968

The animation with constraints could be a little bit tricky. First you need to adjust desired constraints, outside of the animation closure:

NSLayoutConstraint(item: self.placeholder, attribute: .left, relatedBy: .equal, toItem: self.searchBar, attribute: .left, multiplier: 1, constant: 5).isActive = true

Since constraint changes could cause other views change their position, you need ask superview (in the most cases the VC-view) to layout its subviews within the animation closure:

 UIView.animate(withDuration: 2, delay: 1, options: UIViewAnimationOptions.curveEaseOut, animations: {
      self.view.layoutIfNeeded()
 }, completion: nil)

Therefore the superview adjusts subviews positions for you within the animation block.

Upvotes: 4

naturaln0va
naturaln0va

Reputation: 763

In order to animate a NSLayoutConstraintyou need to put setNeedsLayout() in the animation block. You should then move the

NSLayoutConstraint(item: self.placeholder, attribute: .left, relatedBy: .equal, toItem: self.searchBar, attribute: .left, multiplier: 1, constant: 5).isActive = true

to above the animation block like so:

NSLayoutConstraint(item: self.placeholder, attribute: .left, relatedBy: .equal, toItem: self.searchBar, attribute: .left, multiplier: 1, constant: 5).isActive = true
UIView.animate(withDuration: 2, delay: 1, options: UIViewAnimationOptions.curveEaseOut, animations: {
    self.layoutIfNeeded()
}, completion: { (completed) in

})

Hope that helps!

Upvotes: 1

Related Questions