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

use*_*492 25 macos xcode cocoa objective-c swift

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

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

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

blu*_*ome 41

我认为,最简单的方法就是交换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
}
Run Code Online (Sandbox Code Playgroud)

这是选项#1.

如果要使用segue,请创建自定义的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
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是选项#2.

最后一个选项是使用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
            })
        }        
    }
}
Run Code Online (Sandbox Code Playgroud)

然后像这样呈现VC.

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

对于解雇,调用presentingViewControllerdismissViewController:所呈现的VC.

@IBAction func dismissAction(sender: AnyObject) {
    presentingViewController?.dismissViewController(self)    
}
Run Code Online (Sandbox Code Playgroud)

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
        })
    }
}
Run Code Online (Sandbox Code Playgroud)

}

希望这有帮助.


Ely*_*Ely 5

如果您有一个父视图控制器,则可以为其分配子视图控制器,然后使用该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)
    }
}
Run Code Online (Sandbox Code Playgroud)

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

在上面的示例中,情节提要与一个主视图控制器(= self),一个情节提要ID为“ firstController”的子视图控制器以及另一个情节提要ID为“ secondController”的子视图控制器一起使用。

  • @ user14492:我实际上是在自己寻找答案。我看到 StackOverflow 中的所有示例都没有使用现代的 `transition` 方法,所以在弄清楚该方法的实际工作原理后,我无法阻止自己撰写答案:) (2认同)