Moumou
Moumou

Reputation: 1532

UIView animation is done instantly without regards to the duration or delay

I'm having some difficulties animating one of my view's layoutConstraints:

UIView.animate(withDuration: 1, delay: 0, options: UIViewAnimationOptions.curveEaseInOut, animations: {
                self.topLayoutConstraint?.constant = self.currentYPosition
                self.layoutIfNeeded()
                }, completion: nil)

Whatever the duration or the delay that I use, the animation is instantly done (my view jumps from previous position to the new one).

I've checked all the value and they are correct. I've also checked and the animation and completion are called.

Any ideas ?

EDIT:

@objc private func viewDragged(_ recognizer: UIPanGestureRecognizer) {

        let location = recognizer.location(in: self.superview)

        switch recognizer.state {
        case .ended:

            if (recognizer.direction == .Down) {            // Collapsing the slide panel

                currentYPosition = parentViewHeight - minimumVisibleHeight - statusBarHeight - navBarHeight
            }
            else if (recognizer.direction == .Up) {       // Expanding the slide panel

                // Substracting `minimumVisibleHeight` so that the dragable part is hidden behind the navigation bar
                currentYPosition = -minimumVisibleHeight
            }

            self.topLayoutConstraint?.constant = self.currentYPosition
            UIView.animate(withDuration: 1, delay: 0, options: UIViewAnimationOptions.curveEaseInOut, animations: {
                self.layoutIfNeeded()
                }, completion: nil)
            break
        case .began:
            HomeSlidePanelContainerView.draggingPreviousPosition = location.y
        default:
            self.layoutIfNeeded()

            if (location.y < (parentViewHeight - minimumVisibleHeight - statusBarHeight - navBarHeight)
                || location.y > (statusBarHeight + navBarHeight)) {

                currentYPosition -= HomeSlidePanelContainerView.draggingPreviousPosition - location.y
                topLayoutConstraint?.constant = currentYPosition
                self.layoutIfNeeded()
            }
            HomeSlidePanelContainerView.draggingPreviousPosition = location.y
            break
        }

    }

Upvotes: 3

Views: 2063

Answers (3)

Moumou
Moumou

Reputation: 1532

I've managed to find the solution. This might help others so I'm answering my own question.

What I was doing was something like this:

self.topLayoutConstraint?.constant = self.currentYPosition

UIView.animate(withDuration: 1, delay: 0, options: UIViewAnimationOptions.curveEaseInOut, animations: {               
                self.layoutIfNeeded()
}, completion: nil)

As you can see, I'm changing a value, topLayoutConstraint, that is a constraint on self which is a UIView.

Then I'm trying to animate that change by calling self.layoutIfNeeded in an animation closure.

The thing here is that layoutIfNeeded() applies to subviews and not the view itself. So in my case i was trying to animate the layout of self's subviews instead of self itself.

Changed self.layoutIfNeeded() to self.superview?.layoutIfNeeded() and Voilà !!

Upvotes: 9

Haixiao
Haixiao

Reputation: 1

I often use Snapkit or Masonry do autolayout, maybe you can try it.It is familiar with Apple's autolayout, it is awesome!For example sub code I use today:

UIView.animate(withDuration: 1.0, animations: {
 minLabel.snp.updateConstraints { (make) in
            make.top.equalTo(view.snp.centerY)
                    }
})
self.view.layoutIfNeeded()

Upvotes: 0

shallowThought
shallowThought

Reputation: 19602

Set the constraint before the animation block:

self.topLayoutConstraint?.constant = self.currentYPosition

UIView.animate(withDuration: 1, delay: 0, options: UIViewAnimationOptions.curveEaseInOut, animations: {               
                self.layoutIfNeeded()
}, completion: nil)

Upvotes: 0

Related Questions