Search code examples
iosswiftsnapkit

Entire view is animating in from the top-left


Hey there internet reader,

I'm building a small feature where my banner animates in from the top using Snapkit and Combine. In my viewDidLoad, I call setupObservers which creates this publisher below.

Deeper in my app, isShown is toggled so that the publisher fires when the view is seen for the first time, causing not just the banner but the entire view to animate in from the top left, 0,0 position.

I know this is because I'm calling self.view.layoutIfNeeded(), I'm just curious how to mitigate this so I can get the view to load in without animation, then show the banner.

Thanks!

    public override func viewDidLoad() {
        super.viewDidLoad()

        setupObservers()

        viewStore.send(.viewDidLoad)
    }
        viewStore.publisher
            .banner
            .isShown
            .sink { isShown in
                guard self.initLoadFinished else { return }

                UIView.animate(withDuration: Metrics.animationDuration, delay: 0, options: .curveEaseInOut) {
                    self.banner.snp.updateConstraints {
                        if isShown {
                            self.topConstraint = $0.top.equalToSuperview()
                        } else {
                            self.topConstraint = $0.top.equalToSuperview().offset(-Metrics.bannerHeight)
                        }
                    }
                    self.view.layoutIfNeeded()
                }
            }.store(in: &cancellables)

Solution

  • Get setting the constant out of the animation block

    self.banner.snp.updateConstraints {
        if isShown {
             self.topConstraint.update(offset: 0)  
        } else {
             self.topConstraint.update(offset:-Metrics.bannerHeight)
        }
    }  
    UIView.animate(withDuration: Metrics.animationDuration, delay: 0, options: .curveEaseInOut) { 
        self.view.layoutIfNeeded() 
    }