xcode 在视图控制器和 OS X 之间转换

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28454291/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 06:38:21  来源:igfitidea点击:

Transitioning between view controller, OS X

objective-cxcodemacoscocoaswift

提问by user14492

I am trying to write a single window timer application, where when the user presses the start button I want it to show another view controller with countdown etc. I'm also using story board in Xcode, where I have got a segue which connects the start button and the second view controller. However, there are only three different styles i.e. modal, sheet, and pop-over. I want to replace the first view controller the second one in the window. I cannot find a way to do that. I tried using a custom style for the segue, and in that use presentViewController: animator: method but I cannot figure out what to send as the argument for the animator:.

我正在尝试编写一个单窗口计时器应用程序,当用户按下开始按钮时,我希望它显示另一个带有倒计时等的视图控制器。我还在 Xcode 中使用故事板,在那里我有一个连接开始按钮和第二个视图控制器。但是,只有三种不同的样式,即模态、表单和弹出窗口。我想将窗口中的第一个视图控制器替换为第二个视图控制器。我找不到办法做到这一点。我尝试为 segue 使用自定义样式,并在该样式中使用 presentViewController: animator: 方法,但我不知道要发送什么作为 animator: 的参数。

What is the simplest/proper way to transition from one view controller to the other in one window and vice versa?

在一个窗口中从一个视图控制器转换到另一个视图控制器的最简单/正确的方法是什么,反之亦然?

Also in the storyboard when I select a view controller it shows an attribute called "Presentation" which can be multiple and single, what do those represent?

同样在故事板中,当我选择一个视图控制器时,它会显示一个名为“Presentation”的属性,它可以是多个也可以是单个的,这些代表什么?

回答by bluedome

I think the simplest way is that swapping contentViewControllerof NSWindow.

我认为,最简单的方法就是交换contentViewControllerNSWindow

// in NSViewController's subclass
@IBAction func someAction(sender: AnyObject) {
    let nextViewController = ... // instantiate from storyboard or elsewhere

    if let window = view.window where window.styleMask & NSFullScreenWindowMask > 0 {
        // adjust view size to current window
        nextViewController.view.frame = CGRectMake(0, 0, window.frame.width, window.frame.height)
    }

    view.window?.contentViewController = nextViewController
}

This is option #1.

这是选项#1。

If you want to use segue, create custom one and set it to segue class with identifier in IB.

如果要使用segue,请创建自定义的并将其设置为带有IB 标识符的segue 类。

class ReplaceSegue: NSStoryboardSegue {
    override func perform() {
        if let fromViewController = sourceController as? NSViewController {
            if let toViewController = destinationController as? NSViewController {
                // no animation.
                fromViewController.view.window?.contentViewController = toViewController
            }
        }
    }
}

This is option #2.

这是选项#2。

Last option is using presentViewController:animator:of NSViewController. The code below is custom NSViewControllerPresentationAnimatorfor dissolve animation.

最后一个选项是使用presentViewController:animator:NSViewController。下面的代码是NSViewControllerPresentationAnimator为溶解动画定制的。

class ReplacePresentationAnimator: NSObject, NSViewControllerPresentationAnimator {
    func animatePresentationOfViewController(viewController: NSViewController, fromViewController: NSViewController) {
        if let window = fromViewController.view.window {
            NSAnimationContext.runAnimationGroup({ (context) -> Void in
                fromViewController.view.animator().alphaValue = 0
            }, completionHandler: { () -> Void in
                viewController.view.alphaValue = 0
                window.contentViewController = viewController
                viewController.view.animator().alphaValue = 1.0
            })
        }
    }

    func animateDismissalOfViewController(viewController: NSViewController, fromViewController: NSViewController) {
        if let window = viewController.view.window {
            NSAnimationContext.runAnimationGroup({ (context) -> Void in
                viewController.view.animator().alphaValue = 0
                }, completionHandler: { () -> Void in
                    fromViewController.view.alphaValue = 0
                    window.contentViewController = fromViewController
                    fromViewController.view.animator().alphaValue = 1.0
            })
        }        
    }
}

Then present VC like this.

然后像这样呈现VC。

@IBAction func replaceAction(sender: AnyObject) {
    let nextViewController = ... // instantiate from storyboard or elsewhere
    presentViewController(nextViewController, animator: ReplacePresentationAnimator())
}

For dismissal, call presentingViewController's dismissViewController:in the presented VC.

对于解雇,呼叫presentingViewControllerdismissViewController:所呈现的VC。

@IBAction func dismissAction(sender: AnyObject) {
    presentingViewController?.dismissViewController(self)    
}

Swift4 Version

Swift4 版本

class ReplacePresentationAnimator: NSObject, NSViewControllerPresentationAnimator {
func animatePresentation(of viewController: NSViewController, from fromViewController: NSViewController) {
    if let window = fromViewController.view.window {
        NSAnimationContext.runAnimationGroup({ (context) -> Void in
            fromViewController.view.animator().alphaValue = 0
        }, completionHandler: { () -> Void in
            viewController.view.alphaValue = 0
            window.contentViewController = viewController
            viewController.view.animator().alphaValue = 1.0
        })
    }
}

func animateDismissal(of viewController: NSViewController, from fromViewController: NSViewController) {
    if let window = viewController.view.window {
        NSAnimationContext.runAnimationGroup({ (context) -> Void in
            viewController.view.animator().alphaValue = 0
        }, completionHandler: { () -> Void in
            fromViewController.view.alphaValue = 0
            window.contentViewController = fromViewController
            fromViewController.view.animator().alphaValue = 1.0
        })
    }
}

}

}

Hope this help.

希望这有帮助。

回答by Ely

If you have one parent view controller, you can assign child view controllers to it, and use the transitionmethod. Example code, to be placed in viewDidLoad of the parent view controller:

如果您有一个父视图控制器,则可以为其分配子视图控制器,并使用该transition方法。示例代码,放置在父视图控制器的 viewDidLoad 中:

if let firstController = self.storyboard?.instantiateController(withIdentifier: "firstController") as? NSViewController {
    firstController.view.autoresizingMask = [.width, .height]
    firstController.view.frame = self.view.bounds
    self.addChild(firstController)
    self.view.addSubview(firstController.view)
}

if let secondController = self.storyboard?.instantiateController(withIdentifier: "secondController") as? NSViewController {
    self.addChild(secondController)
}

DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
    if let firstController = self.children.first, let secondController = self.children.last {
        self.transition(from: firstController, to: secondController, options: .crossfade, completionHandler: nil)
    }
}

It's essential that the view of the first child controller is being added as sub view to the view of the parent controller, otherwise the transitionmethod doesn't work.

必须将第一个子控制器的视图作为子视图添加到父控制器的视图中,否则该transition方法不起作用。

In the example above, a storyboard is used with one main view controller (= self), one child view controller with storyboard ID "firstController', and another child view controller with storyboard ID "secondController'

在上面的示例中,故事板与一个主视图控制器(= self)、一个故事板 ID 为“firstController”的子视图控制器和另一个故事板 ID 为“secondController”的子视图控制器一起使用