如何在 NSViewController.transition 期间将 NSViewController 固定到 NSPopover 的顶部?

How to pin NSViewController to top of NSPopover during NSViewController.transition?

我一直在尝试在 NSPopover 中创建从一个子视图控制器到另一个子视图控制器的滑动过渡。

我的问题是子视图控制器在转换期间没有粘在 NSPopover 的顶部。它们从底部或顶部开始动画:

预期行为:两个子视图控制器都应在过渡期间保持在顶部,并且应该简单地水平滑动。

这是我写的触发转换的函数:

func loadViewController(_ childViewController: NSViewController, withTransition transitionOptions: NSViewController.TransitionOptions?) {
        addChild(childViewController)
        view.addSubview(childViewController.view)

        childViewController.view.layer?.borderColor = NSColor(calibratedRed: 0, green: 255, blue: 0, alpha: 1).cgColor
        childViewController.view.layer?.borderWidth = 2

        childViewController.view.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
        view.layout()

        let oldViewController = currentViewController
        currentViewController = childViewController

        oldViewController?.view.layer?.borderColor = NSColor(calibratedRed: 255, green: 0, blue: 0, alpha: 1).cgColor
        oldViewController?.view.layer?.borderWidth = 2

        if let oldViewController = oldViewController  {
            transition(from: oldViewController, to: currentViewController!, options: transitionOptions ?? .slideLeft, completionHandler: { [weak oldViewController] in
                oldViewController?.removeFromParent()
                oldViewController?.view.removeFromSuperview()
            })
        }

        NSAnimationContext.runAnimationGroup({ (context) -> Void in
            context.duration = 0.5
            context.allowsImplicitAnimation = true

            self.parentPopover?.contentSize = NSSize(width: childViewController.preferredContentSize.width, height: childViewController.preferredContentSize.height)
        })
    }

知道是什么导致了这个问题吗?我试过玩弄子视图控制器和父视图控制器的约束以及它们的框架大小。我只是不知道我做错了什么。

我已经在此处上传了完整的可重现示例:https://github.com/maximilianschmitt/DebugPopoverAnimation

非常感谢您的帮助!

如果你期待下面的动画

然后只需从动画块中删除内容大小的更新,如下所示

self.parentPopover?.contentSize = NSSize(width: childViewController.preferredContentSize.width, height: childViewController.preferredContentSize.height)
NSAnimationContext.runAnimationGroup({ (context) -> Void in
    context.duration = 0.5
    context.allowsImplicitAnimation = true

}) {
    oldViewController?.removeFromParent()
    oldViewController?.view.removeFromSuperview()
}

更新: 使弹出窗口内容保持动画效果(不需要进行上述更改)

对于这种情况,您唯一需要的是翻转弹出内容视图的坐标系(这是 MasterViewController 的视图)

class PopoverContentView: NSView {
    override var isFlipped: Bool { true }
}

class MasterViewController: NSViewController {
    ...
    override func loadView() {
        self.view = PopoverContentView()
    }