シングルウィンドウタイマーアプリケーションを記述しようとしています。ユーザーがスタートボタンを押したときに、カウントダウンなどの別のビューコントローラーを表示したいのです。また、Xcodeでストーリーボードを使用しています。スタートボタンと2番目のビューコントローラー。ただし、モーダル、シート、ポップオーバーの3つの異なるスタイルしかありません。最初のビューコントローラーをウィンドウの2番目のビューコントローラーに置き換えます。それを行う方法が見つかりません。セグエにカスタムスタイルを使用してみましたが、その中でpresentViewController:animator:メソッドを使用しましたが、animator:の引数として何を送信するかわかりません。
1つのウィンドウで1つのビューコントローラーから別のビューコントローラーに、またはその逆に遷移する最も簡単で適切な方法は何ですか?
また、ストーリーボードでビューコントローラーを選択すると、「プレゼンテーション」という属性が表示されます。これは、複数の場合と単一の場合がありますが、これらは何を表していますか?
最も簡単な方法は、contentViewController
のNSWindow
を入れ替えることです。
// 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
}
これはオプション#1です。
セグエを使用したい場合は、カスタムセグエを作成し、IBの識別子でクラスをセグエに設定します。
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
}
}
}
}
これはオプション#2です。
最後のオプションはNSViewController
のpresentViewController:animator:
を使用しています。以下のコードは、ディゾルブアニメーション用のカスタム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
})
}
}
}
次に、VCこのように提示します。
@IBAction func replaceAction(sender: AnyObject) {
let nextViewController = ... // instantiate from storyboard or elsewhere
presentViewController(nextViewController, animator: ReplacePresentationAnimator())
}
解任するには、提示されたVCでpresentingViewController
のdismissViewController:
を呼び出します。
@IBAction func dismissAction(sender: AnyObject) {
presentingViewController?.dismissViewController(self)
}
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
})
}
}
}
この助けを願っています。
親View Controllerが1つある場合は、子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)
}
}
最初の子コントローラのビューが親コントローラのビューにサブビューとして追加されていることが重要です。そうでない場合、transition
メソッドは機能しません。
上記の例では、ストーリーボードが1つのメインビューコントローラー(=セルフ)、ストーリーボードIDが「firstController」の子ビューコントローラー、ストーリーボードIDが「secondController」の子ビューコントローラーで使用されています。