Animating Auto Layout constraints with NSView.layoutSubtreeIfNeeded() not working on macOS High Sierra

佐手、 提交于 2019-12-07 05:00:57

问题


I have a basic Mac app with a view animation done through Auto Layout:

  • I add a new view to the right of the current view
  • I update the constraints so that the new view ends up filling the window

→ The animation will make it appear as if the view slides in from the right.

The recommended way for animating Auto Layout changes is:

  1. Update the constraints
  2. Use NSAnimationContext.runAnimationGroup()
  3. Set allowsImplicitAnimation to true inside the animation block
  4. Call view.layoutSubtreeIfNeeded() inside the animation block

I 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
        })
    //}
}

回答1:


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
}


来源:https://stackoverflow.com/questions/47283066/animating-auto-layout-constraints-with-nsview-layoutsubtreeifneeded-not-workin

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!