Search code examples
iosswiftautolayoutsnapkit

View not displayed immediately after layoutIfNeeded is called


I'm trying to have a simple slide-down-from-top animation using auto layout (with the help of SnapKit).

Below is the code I use to generate a view, set its constraints and force a reload (thus display) of said view. In the same code cope I change the top constraint to a different value and call layoutIfNeeded in an animation block.

What happens instead though is that the view is displayed at the intended position without any animations whatsoever.

Here is the code called in a method after a short delay (for other purposes):

DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(4), execute: {
    self.view.addSubview(view)
    view.backgroundColor = .black

    view.snp.makeConstraints { (make) -> Void in
        make.left.right.equalToSuperview()
        make.height.equalTo(200)
        make.bottom.equalTo(self.view.snp.top) // Pin view to top to prepare slide-down animation
    }

    view.setNeedsLayout()
    view.layoutIfNeeded()

    view.snp.updateConstraints { (make) -> Void in
        make.bottom.equalTo(self.view.snp.top).offset(200)
    }

    view.setNeedsLayout()

    UIView.animate(withDuration: 5, animations: {
        view.layoutIfNeeded()
    })
})

Solution

  • Thanks to In Swift, how do I animate a UIView with auto-layout like a page sliding in? I found the culprit.

    Although I don't 100% understand why this is, but layoutIfNeeded needs to be called from the superview, not the view itself.

    So calling self.view.layoutIfNeeded() is the correct way. Note that view is the currently being added UIView, whereas self.view is the superview, where view is being added to.