Настройка:
Я пишу приложение на основе документов, ориентированное на OS X 10.11, с использованием раскадровок. В главном окне есть NSToolbar
с 3-сегментным NSSegmentedControl
. При нажатии на сегментированный элемент управления он должен переключать свернутое состояние NSSplitViewItem
в горизонтальное или вертикальное NSSplitView
. Поведение, которого я пытаюсь достичь, такое же, как в Xcode 7, где сегментированный элемент управления на панели инструментов показывает / скрывает представления Navigator / Debug Area / Utilities.
В настоящее время сегментированный элемент управления отправляет действие первому респонденту. Метод действия реализуется подклассом NSSplitViewController
, который затем переключает его состояние NSSplitViewItem
в свернутом состоянии.
Проблема:
Проблема в том, что на панели инструментов также есть NSSearchField
. Если NSSearchField
находится в фокусе или даже если сам сегментированный элемент управления имеет фокус, нажатие на NSSegmentedControl
с курсором не приводит к тому, что метод действия правильно перемещается вверх по цепочке респондентов к подклассу NSSplitViewController
.
Попытки решения:
Раньше я работал над этой проблемой, используя уведомления вместо цели / действия, но в итоге все получилось слишком запутанным. Другая идея - отправить сообщение контроллеру окна, который затем передаст его контроллеру представления содержимого, который передаст его контроллеру представления вертикального разделения, который затем отправит сообщение (при необходимости) контроллеру представления горизонтального разделения. Хотя я знаю, что это сработает, это также выглядело уродливым решением, когда нужно было добавить код в 2 дополнительных файла, которые просто передавали сообщение, я думал, что это то, чего удалось избежать при использовании цепочки респондентов.
Любые идеи будут очень признательны.
Окончательное решение:
Я понял, что связывание действия сегментированного элемента управления с первым респондентом имеет смысл только в том случае, если важен ключевой контекст представления. В этом случае сегментированный элемент управления должен переключать свернутое состояние элементов разделенного представления в нескольких вложенных разделенных представлениях, независимо от того, какое представление является ключевым.
Определите перечисление для представления областей разделенного представления:
enum SplitViewArea : Int {
// The raw values must match the order of the segmented control
case left, top, right
}
Определите протокол, по которому следует переключать разделенную область просмотра:
protocol SplitViewTogglable {
func toggleSplitViewItem(matching area: SplitViewArea)
}
Реализуйте метод сегментированного управляющего действия в контроллере окна:
@IBAction func segmentedControlSelectionStateDidChange(_ sender: Any) {
guard let segmentedControl = sender as? NSSegmentedControl else { return }
guard let area = SplitViewArea(rawValue: segmentedControl.selectedSegment) else { return }
guard let togglable = contentViewController as? SplitViewTogglable else { return }
togglable.toggleSplitViewItem(matching: area)
}
Реализуйте метод протокола SplitViewTogglable
в подклассе NSSplitViewController:
func toggleSplitViewItem(matching area: SplitViewArea) {
switch area {
case .left:
leftSplitViewItem.isCollapsed = !leftSplitViewItem.isCollapsed
case .top:
// Nested NSSplitViewController that adopts SplitViewTogglable
if let togglable = centerSplitViewItem.viewController as? SplitViewTogglable {
togglable.toggleSplitViewItem(matching: area)
}
case .right:
rightSplitViewItem.isCollapsed = !rightSplitViewItem.isCollapsed
}
}