Setting foreground color works only once for NSAttributedString

落爺英雄遲暮 提交于 2019-12-24 18:56:44

问题


The phone part of the string gets the underline attribute, but the color remains red. I've separated the color and underline setAttributes() calls, to make things clear, the same happens when it's one call.

    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)

回答1:


From the doc of setAttributes():

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

So in other words, it replace them, erasing all previously set, so when you add the underline, it removes the color at that range.

Solution, use addAttributes() instead of 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)

Other solution, use two NSAttributedString (I also remove the NSAttributedStringKey in the enum)

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)

Possible issue with the first solution:
range(of:) returns the range of the first occurence only. In other words, if text = "1800 " and phone = "18", you'll get unwanted results. because rangePhone would be from index 0 to 1, and not 7 to 8 in 1800 18. This issue won't happen in the second one.




回答2:


You should not separate the second and the third call of setAttributes, since the latter will overwrite the earlier. Combine the styles in one array:

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

Result:



来源:https://stackoverflow.com/questions/48318561/setting-foreground-color-works-only-once-for-nsattributedstring

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!