【问题标题】:Animating Auto Layout constraints with NSView.layoutSubtreeIfNeeded() not working on macOS High Sierra使用 NSView.layoutSubtreeIfNeeded() 动画自动布局约束在 macOS High Sierra 上不起作用
【发布时间】:2018-04-27 05:47:24
【问题描述】:

我有一个基本的 Mac 应用程序,其视图动画通过自动布局完成:

  • 我在当前视图的右侧添加了一个新视图
  • 我更新了约束,以便新视图最终填满窗口

→ 动画将使它看起来好像视图从右侧滑入。

动画自动布局更改的推荐方法是:

  1. 更新约束
  2. 使用NSAnimationContext.runAnimationGroup()
  3. 在动画块内将allowsImplicitAnimation 设置为true
  4. 在动画块内调用view.layoutSubtreeIfNeeded()

我遵循了这个建议,在 macOS Sierra 上一切正常,但在 macOS High Sierra 上,动画不再发生。相反,视图显示在其最终位置,但没有动画。

我找到了一个解决方法:我使用DispatchQueue.main.async 将动画安排在下一个 runloop 循环中。但是,这似乎是一个 hack,我想知道这里是否还缺少其他东西。

这是我的实际代码:

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

【问题讨论】:

    标签: cocoa autolayout macos-high-sierra nsanimationcontext nsanimation


    【解决方案1】:

    为您尝试制作动画的根视图启用核心动画支持。可以在 Interface Builder 中或以编程方式完成:

    override func viewDidLoad()
    {
        super.viewDidLoad()
        view.wantsLayer = true
    }
    

    【讨论】:

    • 这就是我的解决方案。很容易忘记将 wantsLayer 设置为 true,因为许多动画在没有图层的情况下也能正常工作。但特别是动画自动布局约束需要在带有图层的 NSView 上。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-05
    • 2017-11-07
    • 1970-01-01
    • 2015-02-03
    • 2018-05-10
    相关资源
    最近更新 更多