I have a basic Mac app with a view animation done through Auto Layout:
→ The animation will make it appear as if the view slides in from the right.
The recommended way for animating Auto Layout changes is:
NSAnimationContext.runAnimationGroup()
allowsImplicitAnimation
to true
inside the animation blockview.layoutSubtreeIfNeeded()
inside the animation blockI followed this recommendation and everything worked fine on macOS Sierra, but on macOS High Sierra, the animation does not take place anymore. Instead the view shows up at its final position without the animation.
I found a workaround: I schedule the animation on the next runloop cycle using DispatchQueue.main.async
. However, that seems like a hack and I'm wondering if there is something else I'm missing here.
Here is my actual code:
private func appendSlideViewControllerAnimated(_ viewController:NSViewController, to viewToTheLeft:NSView)
{
// Insert the new view on the very right, just outside the parent:
viewController.view.frame = self.view.bounds
viewController.view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(viewController.view)
viewController.view.topAnchor.constraint( equalTo: view.topAnchor ).isActive = true
viewController.view.bottomAnchor.constraint( equalTo: view.bottomAnchor ).isActive = true
viewController.view.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
viewController.view.leadingAnchor.constraint(equalTo: viewToTheLeft.trailingAnchor).isActive = true
// Update the layout after we just added the view on the right:
view.layoutSubtreeIfNeeded()
// Starting with macOS High Sierra, animating constraint changes for the newly inserted view
// only works if scheduled on the next runloop:
//DispatchQueue.main.async {
// Update the constraints to pin the view to the left:
self.view.removeConstraint(self.activeSlideLeadingConstraint!)
self.activeSlideLeadingConstraint = viewController.view.leadingAnchor.constraint(equalTo: self.view.leadingAnchor)
self.activeSlideLeadingConstraint?.constant = 0
self.activeSlideLeadingConstraint?.isActive = true
NSAnimationContext.runAnimationGroup( { context in
self.isAnimating = true
context.duration = self.slidingAnimationDuration
context.allowsImplicitAnimation = true
self.view.layoutSubtreeIfNeeded()
}, completionHandler: {
viewToTheLeft.removeFromSuperview()
self.clearUndoHistory()
self.updateFirstResponder()
self.isAnimating = false
})
//}
}
Enable Core Animation backing for root view you trying to animate. It can be done in Interface Builder or programmatically:
override func viewDidLoad()
{
super.viewDidLoad()
view.wantsLayer = true
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With