在macOS High Sierra上使用NSView.layoutSubtreeIfNeedd()设置自动布局约束动画



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

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

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

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

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

我遵循了这个建议,在macOS Sierra上一切都很好,但在macOS High Sierra中,动画不再发生。相反,视图显示在其最终位置,而不显示动画。

我找到了一个解决方法:我使用DispatchQueue.main.async将动画安排在下一个运行循环中。然而,这似乎是一个黑客攻击,我想知道我是否还缺少其他东西。

这是我的实际代码:

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

为尝试设置动画的根视图启用核心动画支持。它可以在界面生成器中完成,也可以通过编程方式完成:

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

相关内容

  • 没有找到相关文章

最新更新