makeFirstResponder не всегда срабатывает - PullRequest
0 голосов
/ 17 апреля 2019

У меня есть NSSearchField внутри NSToolbar, который я пытаюсь установить makeFirstResponder, но он работает с перебоями.Время от времени NSSearchField становится первым респондентом без вызова на makeFirstResponder, а makeFirstResponder возвращает true, как если бы оно было успешно установлено.Настройка NSWindow.initialFirstResponder также не сработала.

class ViewController: NSViewController {
    override func viewDidAppear() {
        super.viewDidAppear()
        view.window?.makeFirstResponder(view.window?.windowController?.searchField
    }
}

У меня были согласованные результаты работы при задержке кода с таймером, но это не идеальное решение.

class ViewController: NSViewController {
    override func viewDidAppear() {
        super.viewDidAppear()
        Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { _ in
            self.view.window?.makeFirstResponder(self.windowController?.searchField)
        }
    }
}

Ответы [ 3 ]

1 голос
/ 20 апреля 2019

Я нашел блог , который помог мне найти причину, по которой это происходило. По умолчанию в macOS NSWindow имеет логическое значение isRestorable, которое будет вызывать то, что было последним firstResponder, независимо от того, что установлено как initialFirstResponder или что установлено внутри viewDidAppear и т. Д.

1 голос
/ 17 апреля 2019

Если makeFirstResponder возвращает true, то, скорее всего, это был первый ответчик, по крайней мере, в течение короткого промежутка времени.

Вы можете использовать тот факт, что NSWindow.firstResponder является KVO-совместимым для обнаружения любых изменений в нем с помощью чего-то вроде следующего кода в вашем ViewController классе:

    override func viewDidAppear() {
        super.viewDidAppear()

        self.view.window?.addObserver(self, forKeyPath: "firstResponder", options: [.initial, .new], context: nil)
        self.view.window?.makeFirstResponder(self.windowController?.searchField)
    }

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if keyPath == "firstResponder" {
            print("First responder of window: \(object) is \(change?[NSKeyValueChangeKey.newKey])")
        }
    }
0 голосов
/ 17 апреля 2019

На самом деле, makeFirstResponder всегда делает ваш элемент управления первым респондентом, но это не гарантирует, что следующий элемент управления не сможет стать первым респондентом.

Из того, что вы испытали, когда вы звоните makeFirstResponder в viewDidLoad, но есть некоторые элементы управления, попросят firstResponder после вашего действия. Следовательно, ваши элементы управления потеряют фокус.

Вы можете решить эту проблему, запросив первого респондента в viewDidAppear или задержав 1 секунду.

...