Лучший практический способ проверки элементов NSTouchBar

В AppKit элементы меню и панели инструментов имеют validateMenuItem(_:) а также validateToolbarItem(_:) соответственно. Однако, благодаря новым элементам сенсорной панели, нет такого удобного метода для проверки соответствующих элементов в нужный момент.

Теперь я проверяю элементы сенсорной панели каждый раз, когда я изменяю связанные значения и вызываю метод проверки в didSet (см. следующий пример кода). Но я чувствую, что это не очень хороший способ, потому что связанные значения должны знать, что в зависимости от него есть элемент сенсорной панели.

var foo: Foo? {
    didSet {
        if #available(macOS 10.12.1, *), NSClassFromString("NSTouchBar") != nil {
            self.validateTouchBarItem(identifier: .foo)
        }
    }
}


@available(macOS 10.12.1, *)
func validateTouchBarItem(identifier: NSTouchBarItemIdentifier) {

    guard
        let item = self.touchBar?.item(forIdentifier: identifier),
        let button = item.view as? NSButton
        else { return }

    switch identifier {
    case NSTouchBarItemIdentifier.foo:
        button.isEnabled = (self.foo != nil)

    default: break
    }
}

Другой способ, которым я пользуюсь - это привязка к Какао и KVO, однако, это не всегда хорошо работает.

Итак, мне любопытно, есть ли какой-либо рекомендуемый или стандартный метод проверки элементов сенсорной панели, особенно содержащий NSButton и NSSegmentedControl. Я хочу изменить не только наличие предметов, но иногда и их изображения или цвета в зависимости от ситуации. Как вы проверяете элементы сенсорной панели?

1 ответ

Решение

Я усовершенствовал свою систему проверки сенсорной панели и сделал следующий протокол и расширения.

@available(macOS 10.12.1, *)
protocol TouchBarItemValidations: class {

    func validateTouchBarItem(_ item: NSTouchBarItem) -> Bool
}



@available(macOS 10.12.1, *)
extension NSTouchBarProvider {

    func validateTouchBarItems() {

        guard NSClassFromString("NSTouchBar") != nil else { return }  // run-time check

        guard let touchBar = self.touchBar else { return }

        // validate currently visible touch bar items
        for identifier in touchBar.itemIdentifiers {
            guard let item = touchBar.item(forIdentifier: identifier) as? NSCustomTouchBarItem else { continue }

            item.validate()
        }
    }

}


@available(macOS 10.12.1, *)
extension NSCustomTouchBarItem: NSValidatedUserInterfaceItem {

    func validate() {

        // validate content control
        if let control = self.control,
            let action = control.action,
            let validator = NSApp.target(forAction: action, to: control.target, from: self)
        {
            if let validator = validator as? TouchBarItemValidations {
                control.isEnabled = validator.validateTouchBarItem(self)

            } else if let validator = validator as? NSUserInterfaceValidations {
                control.isEnabled = (validator as AnyObject).validateUserInterfaceItem(self)
            }
        }
    }



    // MARK: Validated User Interface Item Protocol

    public var action: Selector? {

        return self.control?.action
    }


    public var tag: Int {

        return self.control?.tag ?? 0
    }



    // MARK: Private Methods

    private var control: NSControl? {

        return self.view as? NSControl
    }

}


@available(macOS 10.12.1, *)
extension AppDelegate {

    func applicationDidUpdate(_ notification: Notification) {

        // validate touch bar items
        if #available(macOS 10.12.1, *) {
            if let window = NSApp.mainWindow {
                for responder in sequence(first: window.firstResponder, next: { $0.nextResponder }) {
                    responder.validateTouchBarItems()
                }
            }
        }
    }
}

Вы должны изменить AppDelegate's applicationDidUpdate(:_) если у вас уже есть, но кроме этого, ничего сложного добавить. Теперь вы можете использовать validateTouchBarItem(_:) или нормально validateUserInterfaceItem(_:) проверить свои собственные элементы сенсорной панели!

Я полагаю, это хорошо работает, по крайней мере, для моих требований.

Другие вопросы по тегам