Подтвердить что ты не робот

Переход между контроллером представления, OS X

Я пытаюсь написать приложение таймера одиночного окна, где, когда пользователь нажимает кнопку запуска, я хочу, чтобы он показывал другой контроллер просмотра с обратным отсчетом и т.д. Я также использую панель рассказов в Xcode, где у меня есть segue который соединяет кнопку запуска и второй контроллер. Тем не менее, существует только три разных стиля: модальный, листовой и всплывающий. Я хочу заменить первый контроллер представления вторым в окне. Я не могу найти способ сделать это. Я пробовал использовать пользовательский стиль для segue и при использовании метода presentViewController: animator:, но я не могу понять, что отправить в качестве аргумента для аниматора:.

Каков самый простой/правильный способ перехода от одного контроллера представления к другому в одном окне и наоборот?

Также в раскадровке, когда я выбираю контроллер вида, он показывает атрибут под названием "Презентация", который может быть кратным и одиночным, что они представляют?

4b9b3361

Ответ 1

Я думаю, что самый простой способ - это обмен contentViewController из NSWindow.

// in NSViewController 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.

Если вы хотите использовать segue, создайте пользовательский и установите для него класс segue с идентификатором в 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.

Последний вариант использует 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
            })
        }        
    }
}

Тогда представьте VC вот так.

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

Для увольнения вызовите presentingViewController dismissViewController: в представленном VC.

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

}

Надеюсь, это поможет.

Ответ 2

Если у вас есть один родительский контроллер представления, вы можете назначить ему дочерние контроллеры представления и использовать метод 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 не работает.

В приведенном выше примере раскадровка используется с одним контроллером основного вида (= self), одним дочерним контроллером представления с идентификатором раскадровки "firstController" и другим дочерним контроллером представления с идентификатором раскадровки "secondController".