设置前景色仅对 NSAttributedString 有效一次

Setting foreground color works only once for NSAttributedString

字符串的phone部分得到下划线属性,但颜色保持红色。我已经将颜色和下划线分开 setAttributes() 调用,为了清楚起见,当它是一个调用时也会发生同样的情况。

    let text = "call "
    let phone = "1800-800-900"

    let attrString = NSMutableAttributedString(string: text + phone, attributes: nil)
    let rangeText = (attrString.string as NSString).range(of: text)
    let rangePhone = (attrString.string as NSString).range(of: phone)

    attrString.setAttributes([NSAttributedStringKey.foregroundColor: UIColor.red],
                             range: rangeText)

    attrString.setAttributes([NSAttributedStringKey.foregroundColor: UIColor.blue],
                             range: rangePhone)

    attrString.setAttributes([NSAttributedStringKey.underlineStyle: NSUnderlineStyle.styleSingle.rawValue],
                             range: rangePhone)

不应该分开 setAttributes 的第二次和第三次调用,因为后者会覆盖前面的。将样式组合在一个数组中:

attrString.setAttributes([.foregroundColor: UIColor.blue,
                          .underlineStyle: NSUnderlineStyle.styleSingle.rawValue],
                          range: rangePhone)

结果:

来自 setAttributes() 的文档:

These new attributes replace any attributes previously associated with the characters in aRange.

所以换句话说,它会替换它们,擦除之前设置的所有内容,因此当您添加下划线时,它会删除该范围内的颜色。

解决方法,用addAttributes()代替setAttributes()

let text = "call "
let phone = "1800-800-900"

let attrString = NSMutableAttributedString(string: text + phone, attributes: nil)
let rangeText = (attrString.string as NSString).range(of: text)
let rangePhone = (attrString.string as NSString).range(of: phone)

attrString.addAttributes([NSAttributedStringKey.foregroundColor: UIColor.red],
                         range: rangeText)

attrString.addAttributes([NSAttributedStringKey.foregroundColor: UIColor.blue],
                         range: rangePhone)

attrString.addAttributes([NSAttributedStringKey.underlineStyle: NSUnderlineStyle.styleSingle.rawValue],
                         range: rangePhone)

其他解决方案,使用两个NSAttributedString(我也删除了枚举中的NSAttributedStringKey

let textAttrStr = NSAttributedString(string:text, attributes:[.foregroundColor: UIColor.red])
let phoneAttrStr = NSAttributedString(string:phone, attributes:[.foregroundColor: UIColor.blue,
                                                               .underlineStyle: NSUnderlineStyle.styleSingle.rawValue])

let finalAttrStr = NSMutableAttributedString.init(attributedString: textAttrStr)
finalAttrStr.append(phoneAttrStr)

第一个解决方案可能存在的问题:
range(of:) returns 仅限第一次出现的范围。 换句话说,如果 text = "1800 " 和 phone = "18",您将得到不需要的结果。因为 rangePhone 将从索引 0 到 1,而不是 1800 18 中的 7 到 8。第二个不会出现这个问题