Как представить ViewControllerAsSheet на OSX Маверикс?
Это длинная история, но, чтобы сократить ее; мое первое OSX-приложение было написано (на Yosemite) в Swift с использованием раскадровки, пока я не узнал, что мое (законченное) приложение не будет работать на Mavericks. Мне нужно работать на Mavericks, поэтому я заменил раскадровку на NIB.
Моя проблема с segues; Я использовал сегменты типа листа, чтобы показать другие контроллеры представления на листе поверх контроллера основного вида. Вызов метода presentViewControllerAsSheet в NSViewController является хорошей заменой, поскольку он выглядит так же, но этот API был представлен в Yosemite - поэтому мне нужно разобраться, как это сделать для Mavericks.
В действии для кнопки на главном экране я попытался использовать begin Sheet следующим образом:
secondViewController = SecondViewController(nibName: "SecondViewController", bundle: nil)
self.view.window?.beginSheet(secondViewController!view.window!, completionHandler: nil)
Но второе окно контроллера представления является нулевым во время выполнения. Я попытался добавить новый контроллер представления как подпредставление к окну приложения, но это нераспознанный селектор:
NSApplication.sharedApplication().windows[0].addSubView(secondViewController!.view)
Я искал все выше и ниже описания того, как показать лист, и все, что я могу найти, это: Может ли контроллер представления владеть листом? но мне жаль признаться, что я не понимаю ответ. Кто-нибудь может мне помочь с некоторым рабочим кодом? Я начинаю беспокоиться, что я пытаюсь сделать что-то необычное, но на Yosemite все выглядит нормально, так как же люди делали это до того, как Yosemite был выпущен?
РЕДАКТИРОВАТЬ Я до сих пор не нашел решения, поэтому я собрал небольшое приложение, которое показывает мои проблемы.
В AppDelegate.swift:
class AppDelegate: NSObject, NSApplicationDelegate {
@IBOutlet weak var window: NSWindow!
var mainViewController: FirstView!
func applicationDidFinishLaunching(aNotification: NSNotification) {
mainViewController = FirstView(nibName:"FirstView", bundle: nil)
window.contentView = mainViewController.view
mainViewController.view.frame = (window.contentView as! NSView).bounds
}
}
В FirstView.swift (связанный NIB имеет кнопку "открыть лист")
class FirstView: NSViewController {
var secondView: SecondView?
var secondWindow: SecondWinCon?
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func pressButton(sender: AnyObject) {
secondView = SecondView(nibName: "SecondView", bundle: nil)!
// method 1 - this is the behaviour I want (but it only works on OSX 10.10)
// presentViewControllerAsSheet(secondView!)
// method 2 - this just creates a floating window
// self.view.addSubview(secondView!.view)
// self.view.window?.beginSheet(secondView!.view.window!, completionHandler: nil)
// method 3 - this also creates a floating window
secondWindow = SecondWinCon(windowNibName: "SecondWinCon")
self.view.window?.beginSheet(secondWindow!.window!, completionHandler: nil)
}
}
В SecondView.swift (связанный NIB имеет кнопку "Закрыть")
class SecondView: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func dismissPressed(sender: AnyObject) {
if (presentingViewController != nil) {
presentingViewController?.dismissViewController(self)
} else {
self.view.window?.sheetParent?.endSheet(self.view.window!)
}
}
}
В SecondWinCon.swift (связанный NIB пуст)
class SecondWinCon: NSWindowController {
var secondView: SecondView?
override func windowDidLoad() {
super.windowDidLoad()
secondView = SecondView(nibName: "SecondView", bundle: nil)!
self.window?.contentView.addSubview(secondView!.view)
}
}
Если метод 1 не закомментирован, вы увидите поведение, которое я пытаюсь эмулировать (помните, что оно работает только в OS X 10.10). Метод 2 или 3 отображает второе представление, но не в виде листа.
2 ответа
Если вы попали сюда в поисках решения, я почти подошел к методу 3. Важным шагом, который я пропустил, было отключение "Visible At Launch" в NIB NSWindowController (это атрибут NSWindow). В моем примере кода это было в SecondWinCon.nib.
У меня та же проблема, и я обнаружил, что, возможно, это не проблема, связанная с просмотром жизненного цикла. Когда я вызываю presentViewControllerAsSheet в viewDidLoad, лист не будет показан, и вы получите это в консоли:
Не удалось установить (contentViewController) определяемое пользователем проверяемое свойство для (NSWindow): presentViewController:animator:: View 'представление не находится в иерархии окна / представления.
Если вы активируете это в viewWillAppear или viewDidAppear, это совершенно не проблема.
ОБНОВИТЬ
Хорошо, давайте проясним это.
Для этой первоначальной раскадровки NSWindowController связан с контроллером представления, представьте его как корневой контроллер представления (RootVC). Создайте другой желаемый контроллер представления в виде листа в раскадровке (SheetVC). в viewWillAppear или viewDidAppear RootVC, [self presentViewControllerAsSheet: SheetVC]
Лист покажет, дополнительный код не требуется.