Этот ответ не является решением проблемы NSLinkAttributeName
, игнорируя пользовательские цвета, это альтернативное решение для цветных интерактивных слов в NSAttributedString
.
С помощью этого обходного пути мы не используем NSLinkAttributeName
вообще, так как она заставляет стиль, мы не хотим.
Вместо этого мы используем пользовательские атрибуты, и мы подклассифицируем NSTextField
/NSTextView
, чтобы обнаружить атрибуты под щелчком мыши и действовать соответственно.
Существует несколько ограничений, очевидно: вы должны иметь возможность подклассифицировать поле/представление, переопределить mouseDown
и т. Д., Но «он работает для меня» в ожидании исправления.
При подготовке NSMutableAttributedString
, где бы вы установили в NSLinkAttributeName
, установить связь как атрибут с пользовательским ключом вместо:
theAttributedString.addAttribute("CUSTOM", value: theLink, range: theLinkRange)
theAttributedString.addAttribute(NSForegroundColorAttributeName, value: NSColor.orange, range: theLinkRange)
theAttributedString.addAttribute(NSCursorAttributeName, value: NSCursor.arrow(), range: theLinkRange)
цвет и содержание для ссылки установлен. Теперь мы должны сделать его интерактивным.
Для этого подкласс NSTextView
и переопределить mouseDown(with event: NSEvent)
.
Мы получим местоположение события мыши в окне, найдите индекс символа в текстовом представлении в этом месте и попросите атрибуты символа в этом индексе в строке атрибута текстового вида.
class MyTextView: NSTextView {
override func mouseDown(with event: NSEvent) {
// the location of the click event in the window
let point = self.convert(event.locationInWindow, from: nil)
// the index of the character in the view at this location
let charIndex = self.characterIndexForInsertion(at: point)
// if we are not outside the string...
if charIndex < super.attributedString().length {
// ask for the attributes of the character at this location
let attributes = super.attributedString().attributes(at: charIndex, effectiveRange: nil)
// if the attributes contain our key, we have our link
if let link = attributes["CUSTOM"] as? String {
// open the link, or send it via delegate/notification
}
}
// cascade the event to super (optional)
super.mouseDown(with: event)
}
}
Всё.
В моем случае мне нужно было настроить разные слова с разными цветами и типами ссылок, поэтому вместо передачи только ссылки в виде строки я передаю структуру, содержащую ссылку и дополнительную метаинформацию, но идея такая же.
Если вам нужно использовать NSTextField
вместо NSTextView
, это немного сложнее найти местоположение события клика. Решением является создание NSTextView
внутри NSTextField
и оттуда использовать ту же технику, что и раньше.
class MyTextField: NSTextField {
var referenceView: NSTextView {
let theRect = self.cell!.titleRect(forBounds: self.bounds)
let tv = NSTextView(frame: theRect)
tv.textStorage!.setAttributedString(self.attributedStringValue)
return tv
}
override func mouseDown(with event: NSEvent) {
let point = self.convert(event.locationInWindow, from: nil)
let charIndex = referenceView.textContainer!.textView!.characterIndexForInsertion(at: point)
if charIndex < self.attributedStringValue.length {
let attributes = self.attributedStringValue.attributes(at: charIndex, effectiveRange: nil)
if let link = attributes["CUSTOM"] as? String {
// ...
}
}
super.mouseDown(with: event)
}
}
При использовании 'NSTextView', вы должны установить' свойство linkTextAttributes'. Когда «NSTextField» сфокусирован и может быть отредактирован, текст отображается в «NSTextView», который использует свой 'linkTextAttributes' (синий, подчеркнутый и ручной курсор по умолчанию). – Willeke
@Willeke Спасибо, к сожалению, я уже пробовал переопределить linkTextAttributes, это хорошее решение, но оно применяет одни и те же атрибуты ко всем ссылкам в атрибутной строке, и мне нужно иметь возможность устанавливать разные. Дело в том, что * ваш ответ на мой другой вопрос работал до недавнего времени *, большой мистерий вот почему тот же самый код, на который вы ответили, больше не работает. :) – Moritz
Ох. Ссылка помечена оранжевым цветом в Xcode 7. Она синяя в Xcode 8. Я подаю радар ... Извините, что беспокоил вас этим, @Willeke ... – Moritz