Swift macOS SegmentedControl Действие не вызывается
Описание
Я пытаюсь использовать NSSegmentedControls
для перехода между дочерними ViewControllers. ParentViewController
находится в Main.storyboard
и ChildViewControllers
расположены в Assistant.storyboard
, Каждый Child ViewController имеет SegmentedControl, разделенный на 2 сегмента, и их основное использование заключается в перемещении между Child ViewControllers. Таким образом, они настроены как momentaryPushIn
вместо того, чтобы выбрать один. Каждый Child ViewController использует делегат для связи с ParentViewController.
Поэтому в ParentViewController я добавил Child ViewControllers следующим образом:
/// The View of the ParentViewController configured as NSVisualEffectView
@IBOutlet var visualEffectView: NSVisualEffectView!
var assistantChilds: [NSViewController] {
get { return [NSViewController]() }
set(newValue) {
for child in newValue { self.addChild(child) }
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
addAssistantViewControllersToChildrenArray()
}
override func viewWillAppear() {
visualEffectView.addSubview(self.children[0].view)
self.children[0].view.frame = self.view.bounds
}
private func addAssistantViewControllersToChildrenArray() -> Void {
let storyboard = NSStoryboard.init(name: "Assistant", bundle: nil)
let exampleChild = storyboard.instantiateController(withIdentifier: "ExampleChild") as! ExampleChildViewController
let exampleSibling = storyboard.instantiateController(withIdentifier: "ExampleSibling") as! ExampleSiblingViewController
exampleChild.navigationDelegate = self
exampleSibling.navigationDelegate = self
assistantChilds = [exampleChild, exampleSibling]
}
Все идет нормально. ExampleChildViewController
имеет NSTextField
пример. Пока я нахожусь в области действия TextField, я могу запустить действие SegmentedControls. Навигация вперед и назад, как и должно быть. Но как только я покину область TextField, я все еще могу щелкнуть по сегментам, но они не вызывают никаких действий. Они должны иметь возможность перемещаться вперед и назад, даже если TextField не является текущим "первым ответчиком" приложения. Я думаю, что здесь что-то упущено, я надеюсь, что кто-нибудь может мне помочь с этим. Я знаю, что проблема не в NSSegmentedControl
потому что я вижу то же самое поведение с NSButton
, который настроен как переключатель / флажок, в SiblingViewController. Я просто понятия не имею, что я делаю неправильно.
Я впервые задаю себе вопрос здесь, поэтому я надеюсь, что то, что я делаю, хорошо для достижения прогресса в решении. Дайте мне знать, если я смогу сделать что-то лучше / по-другому или мне нужно предоставить больше информации о чем-то.
Заранее спасибо!
Дополнительная информация
Для полноты картины:
ParentViewController
сам встраивается вContainerView
, который принадлежитRootViewController
, Я не могу себе представить, что это имеет какое-либо значение, но таким образом мы не пропускаем что-то.На самом деле я не показываю навигационное действие, потому что хочу сделать его максимально простым. Кроме того, действие не проблема, оно делает то, что я хочу. Поправь меня, если я не прав с этим.
Возможные решения, которые я нашел во время исследования, которые мне не помогли:
- Установка window.delegate для Child ViewControllers в NSApp.windows.first?.Delegate
- Установка Child ViewController в
becomeFirstResponder
в егоfunc viewWillAppear()
visualEffectView.addSubview(self.children[0].view, positioned: NSWindow.OrderingMode.above, relativeTo: nil
)
Связанные проблемы / темы, которые я нашел во время исследования:
- Основной сегментарный контроль не работает
- Добавление и удаление дочерних контроллеров представления
- NSSegmentedControl - Странный вид при размещении в режиме размытия
- Как настроить первый респондент для NSTextView в Swift?
- Как использовать #selector в Swift 2.2 для первого респондента
- Доступ к методам, действиям и / или выходам с других контроллеров с помощью swift
- Как использовать дочерние контроллеры представления в Swift 4.0 программно
- Контроллеры Контейнеров
- проблемы с контейнером
- Управление NSTabViewController из родительского представления
- Как определить, когда NSTextField имеет фокус или его содержимое выбрано какао
1 ответ
РЕШЕНИЕ
let parentViewControllerInstance = self.parent as! ParentViewController
segmentedControl.target = parentViewControllerInstance
В моем случае мне просто нужно было установить делегата в качестве цели sendAction
метод.
Фон
Хорошо, после нескольких часов чтения документации AppKit я теперь могу ответить на свой вопрос.
Во-первых, отладка пользовательского интерфейса показала, что проблема определенно не в ViewHierarchy.
Поэтому я попытался подумать о природе NSButton и NSSegmentedControl. В какой-то момент я заметил, что оба являются подклассами NSControl.
class NSSegmentedControl : NSControl
class NSButton : NSControl
Документация AppKit гласит:
обсуждение
Кнопки - это стандартный элемент управления, используемый для запуска действий в вашем приложении. Вы можете настроить кнопки со многими различными визуальными стилями, но их поведение одинаково. При нажатии кнопка вызывает метод действия связанного целевого объекта. (...) Вы используете метод действия для выполнения задач вашего приложения.
Жирный текст указывает на ключ решения - связанного с ним целевого объекта. Обычно я определяю действие элемента управления следующим образом:
button.action = #selector(someFunc(_:))
Это заставляет экземпляр NSControl вызывать это:
func sendAction(_ action: Selector?, to target: Any?) -> Bool
Описание параметров из документации:
параметры
Действие
Селектор для вызова на цель. Если селектор равен NULL, сообщение не отправляется.
цель
Целевой объект для получения сообщения. Если объект имеет значение nil, приложение ищет в цепочке респондента объект, способный обработать сообщение. Для получения дополнительной информации о диспетчерских действиях см. Описание класса для NSActionCell.
В заключение у экземпляра NSControl, который запускал метод действия (в моем случае NSSegmentedControl), не было цели для отправки своего действия. Таким образом, он мог только отправить свой метод действия через цепочку респондента - который, очевидно, был нулевым, пока первый респондент находился в другом представлении.