本文介绍了使用NSView.layoutSubtreeIfNeeded()对自动布局约束进行动画处理在macOS High Sierra上不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个基本的Mac应用程序,该应用程序具有通过自动版式完成的视图动画:

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:

  1. 更新约束
  2. 使用NSAnimationContext.runAnimationGroup()
  3. 在动画块内将allowsImplicitAnimation设置为true
  4. 在动画块内调用view.layoutSubtreeIfNeeded()
  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

我遵循了此建议,并且在macOS Sierra上一切正常,但是在macOS High Sierra上,动画不再发生.取而代之的是,视图在没有动画的情况下显示在其最终位置.

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.

我找到了一种解决方法:我使用DispatchQueue.main.async将动画安排在下一个运行循环周期中.但是,这似乎是一种黑客行为,我想知道这里是否还有其他遗漏之处.

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.

这是我的实际代码:

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

推荐答案

为要设置动画的根视图启用Core Animation支持.可以在Interface Builder中完成,也可以通过编程方式完成:

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
}

这篇关于使用NSView.layoutSubtreeIfNeeded()对自动布局约束进行动画处理在macOS High Sierra上不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-31 01:20