Захват всех событий изменения выбора для NSTextView, в том числе вызванных перетаскиванием мышью

У меня есть NSViewRepresentable, который содержит NSScrollView с NSTextView внутри.

struct MultilineTextField: NSViewRepresentable {
    typealias NSViewType = NSScrollView
    private let scrollView = NSScrollView()
    private let textView = NSTextView()
    @Binding var text: String
    @Binding var loc: NSRange
    func makeNSView(context: Context) -> NSScrollView {
        textView.string = text
        textView.delegate = context.coordinator
        scrollView.documentView = textView
        return scrollView
    }
    func updateNSView(_ scrollView: NSScrollView, context: Context) {}
    func makeCoordinator() -> Coordinator {
        return Coordinator(self)
    }
    class Coordinator: NSObject, NSTextViewDelegate {
        let textField: MultilineTextField
        init(_ textField: MultilineTextField) {
            self.textField = textField
        }
        func textDidChange(_ notification: Notification) {
            textField.text = textField.textView.string
        }
        func textViewDidChangeSelection(_ notification: Notification) {
            DispatchQueue.main.async {
                self.textField.loc = self.textField.textView.selectedRange()
            }
        }
    }
}

Я пытаюсь извлечь selectedRange из NSTextView для отображения в другом представлении, например:

Text(String(loc.location))

Он работает, когда selectedRange изменяется с помощью клавиш со стрелками и при нажатии мыши и мыши вверх, но похоже, что textViewDidChangeSelection не вызывается, когда вы перетаскиваете мышь по тексту. В результате отображаемое значение loc.location не изменяется при перетаскивании, пока мышь не будет поднята.

В качестве обходного пути я попытался создать подкласс NSTextView, чтобы переопределить mouseMoved метод, но похоже, что он тоже по какой-то причине не вызывается.

Чтобы убедиться, что selectedRange действительно обновляется при перетаскивании мышью, я попытался постоянно обновлять loc (это в классе Coordinator):

init(_ textField: MultilineTextField) {
    self.textField = textField
    super.init()
    updateSelection()
}
func updateSelection() {
    DispatchQueue.main.async {
        self.textField.loc = self.textField.textView.selectedRange()
        self.updateSelection()
    }
}

Этот код действительно работает, но без причины использует 100% ЦП.

Есть ли способ получать уведомления об selectedRange изменениях в случае перетаскивания мышью?


person bjb568    schedule 27.12.2020    source источник
comment
@Asperi Это изменится при перетаскивании назад, но в любом случае loc.length тоже не изменится.   -  person bjb568    schedule 27.12.2020
comment
Насколько я понимаю, представимое построено неправильно - свойства NS * будут воссоздаваться каждый раз при обновлении представления. См. Далее рабочий подход, который вы можете расширить для своих нужд stackoverflow.com/a/63761738/12299030.   -  person Asperi    schedule 27.12.2020