Swift NSLinkAttributeName的NSAttributeString中忽略了颜色属性

Swift NSLinkAttributeName的NSAttributeString中忽略了颜色属性,swift,cocoa,xcode8,nsattributedstring,nstextfield,Swift,Cocoa,Xcode8,Nsattributedstring,Nstextfield,在NSAttributedString中,一系列字母具有链接属性和自定义颜色属性 在使用Swift 2的Xcode 7中,它可以工作: 在使用Swift 3的Xcode 8中,链接的自定义属性颜色始终被忽略(在屏幕截图中应为橙色) 下面是测试代码 Swift 2,Xcode 7: import Cocoa import XCPlayground let text = "Hey @user!" let attr = NSMutableAttributedString(string: tex

NSAttributedString
中,一系列字母具有链接属性和自定义颜色属性

在使用Swift 2的Xcode 7中,它可以工作:

在使用Swift 3的Xcode 8中,链接的自定义属性颜色始终被忽略(在屏幕截图中应为橙色)

下面是测试代码

Swift 2,Xcode 7:

import Cocoa
import XCPlayground

let text = "Hey @user!"

let attr = NSMutableAttributedString(string: text)
let range = NSRange(location: 4, length: 5)
attr.addAttribute(NSForegroundColorAttributeName, value: NSColor.orangeColor(), range: range)
attr.addAttribute(NSLinkAttributeName, value: "http://somesite.com/", range: range)

let tf = NSTextField(frame: NSRect(x: 0, y: 0, width: 200, height: 50))
tf.allowsEditingTextAttributes = true
tf.selectable = true
tf.stringValue = text
tf.attributedStringValue = attr

XCPlaygroundPage.currentPage.liveView = tf
Swift 3,Xcode 8:

import Cocoa
import PlaygroundSupport

let text = "Hey @user!"

let attr = NSMutableAttributedString(string: text)
let range = NSRange(location: 4, length: 5)
attr.addAttribute(NSForegroundColorAttributeName, value: NSColor.orange, range: range)
attr.addAttribute(NSLinkAttributeName, value: "http://somesite.com/", range: range)

let tf = NSTextField(frame: NSRect(x: 0, y: 0, width: 200, height: 50))
tf.allowsEditingTextAttributes = true
tf.isSelectable = true
tf.stringValue = text
tf.attributedStringValue = attr

PlaygroundPage.current.liveView = tf

我已经向苹果公司发送了一份错误报告,但在此期间,如果有人对Xcode 8的修复或解决办法有想法,那就太好了。

这个答案并不是对
NSLinkAttributeName
忽略自定义颜色问题的修复,它是在
nsattributestring
中添加彩色可点击单词的替代解决方案


在这种解决方法中,我们根本不使用
NSLinkAttributeName
,因为它强制使用我们不想要的样式

相反,我们使用自定义属性,并将
NSTextField
/
NSTextView
子类化,以便在鼠标单击下检测属性并相应地执行操作

显然,有几个限制:您必须能够对字段/视图进行子类化,覆盖
mouseDown
,等等,但在等待修复时“它对我有效”

在准备
nsmutableAttributeString
时,如果要设置
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(使用事件: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)
    }

}

苹果开发者回答:

请知道,我们的工程团队已根据提供的信息确定此问题的行为符合预期

他们解释了为什么它以前有效,但现在不再有效:

不幸的是,以前的行为(属性化字符串范围,以自定义颜色呈现NSLinkAttributeName)没有得到明确支持。它之所以能够正常工作,是因为NSTextField仅在字段编辑器存在时才呈现链接;如果没有字段编辑器,我们将返回NSForegroundColorAttributeName指定的颜色

版本10.12更新了NSLayoutManager和NSTextField,以使用默认链接外观呈现链接,类似于iOS。()

为了提高一致性,预期的行为是使用默认链接外观绘制表示链接(通过NSLinkAttributeName指定)的范围。因此,当前行为是预期行为


(emphasis mine)

使用
NSTextView
时,必须设置
linkTextAttributes
属性。当一个
NSTextField
被聚焦并且可以编辑时,文本将显示在
NSTextView
中,该视图使用其
linktexttributes
(默认为蓝色,带下划线和手形光标)。@Willeke谢谢,不幸的是我已经尝试覆盖linktexttributes,这是一个很好的解决方案,但它将相同的属性应用于属性字符串中的所有链接,并且我需要能够设置不同的属性。问题是,你对我的另一个问题的回答一直有效,直到最近,这里最大的疑问是为什么你回答的完全相同的代码不再有效哦Xcode 7中的链接是橙色的。它在Xcode 8中是蓝色的。我正在整理雷达。。。很抱歉打扰您,@Willeke…
“htpp”
???下划线也是新的。它过去是没有下划线的(如您的第一个屏幕截图所示)。基本上,他们已经使文本视图链接看起来像一个标签链接。这可能是故意的;以前很混乱,谢谢!非常有用的信息。@Apple:请给我们这个颜色好吗!因此,我们可以同时保持一致性和定制!谢谢@Eric Aya。我刚刚找到了我想要的解决方案。再次感谢!好主意!最后,我需要添加两件事来处理文本字段:(1)设置自定义文本视图文本容器的
lineFragmentPadding
;(2) 将段落样式添加到属性字符串,该属性字符串的
lineBreakMode
设置为
NSLineBreakStrategyPushOut
(对于>=11.0,请使用
NSLineBreakStrategyStandard
)。这些东西修复了多行标签的一些小故障。
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)
    }

}