Swift4中修改UITextView内NSAttributedStringKey.link颜色求助
解决UITextView中话题链接颜色不生效的问题
嘿,我看了你这段给UITextView加#话题链接的代码,思路是对的,但为啥颜色没生效?核心原因是UITextView自带的linkTextAttributes会覆盖你在富文本里设置的前景色,另外还有几个小细节需要调整,下面给你一步步修复:
1. 搞定颜色不生效的核心问题
你在富文本里设置了红色,但UITextView默认会用自己的链接样式(比如蓝色带下划线)覆盖它。所以在给txt_text赋值attributedText之后,必须显式设置linkTextAttributes,把链接颜色指定为红色,还可以顺便去掉下划线(如果不需要的话):
self.txt_text.linkTextAttributes = [ .foregroundColor: UIColor.red, .underlineStyle: NSUnderlineStyle.none.rawValue // 可选,不想有下划线就加这个 ]
2. 优化代码里的小细节
(1)URL创建更安全
你直接用话题文本生成URL,万一话题里有特殊字符(比如中文、空格),URL会创建失败。建议用自定义的URL scheme,比如tag://开头,这样既安全,后面处理点击也更容易区分:
attributedString.addAttribute(.link, value: URL(string: "tag://\(String(HasTagText))")! , range: wordRange)
(2)简化属性写法
你写的NSAttributedStringKey(rawValue: NSAttributedStringKey.foregroundColor.rawValue)太啰嗦了,Swift 4+直接用.foregroundColor就行,代码更清爽。
(3)必须实现链接点击的代理方法
要让链接真的能点击,你得在UITextViewDelegate里实现这个方法,不然点击了也没反应:
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool { // 识别我们自定义的tag scheme if URL.scheme == "tag" { let tag = URL.host ?? "" print("点了话题:#\(tag)") // 这里加你自己的逻辑,比如跳转到话题详情页 return false // 不让系统默认跳转,我们自己处理 } return true }
完整修复后的代码
class YourViewController: UIViewController, UITextViewDelegate { @IBOutlet weak var txt_text: UITextView! override func viewDidLoad() { super.viewDidLoad() txt_text.delegate = self let mainString = "test this text in #nishant #waooo good to #UUUUUU" let attributedString = NSMutableAttributedString(string: mainString) // 设置全局字体 let font = UIFont(name: "verdana", size: 13.0)! attributedString.addAttribute(.font, value: font, range: NSRange(location: 0, length: mainString.utf16.count)) // 匹配#开头的话题 guard let regex = try? NSRegularExpression(pattern: "#(\\w+)", options: []) else { return } let matches = regex.matches(in: mainString, options: [], range: NSRange(location: 0, length: mainString.utf16.count)) for match in matches { let wordRange = match.range(at: 0) guard let tagRange = mainString.rangeFromNSRange(nsRange: wordRange) else { continue } let tagText = mainString[tagRange] // 设置链接和颜色 attributedString.addAttribute(.link, value: URL(string: "tag://\(tagText)")! , range: wordRange) attributedString.addAttribute(.foregroundColor, value: UIColor.red, range: wordRange) } // 关键:设置UITextView的链接样式,覆盖默认的蓝色下划线 txt_text.linkTextAttributes = [ .foregroundColor: UIColor.red, .underlineStyle: NSUnderlineStyle.none.rawValue ] txt_text.attributedText = attributedString } // 处理话题链接的点击事件 func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool { if URL.scheme == "tag" { let tag = URL.host ?? "" print("点击了话题:#\(tag)") // 这里添加你的业务逻辑,比如跳转话题页面 return false } return true } } extension String { func nsRange(from range: Range<String.Index>) -> NSRange? { let utf16view = self.utf16 if let from = range.lowerBound.samePosition(in: utf16view), let to = range.upperBound.samePosition(in: utf16view) { return NSMakeRange(utf16view.distance(from: utf16view.startIndex, to: from), utf16view.distance(from: from, to: to)) } return nil } func rangeFromNSRange(nsRange : NSRange) -> Range<String.Index>? { return Range(nsRange, in: self) } }
额外提醒
- 别忘了确保你的
UITextView的isSelectable属性是true(默认就是true,但如果手动改了false的话,链接点不动)。 - 如果需要支持中文话题,把正则表达式改成
#([\\w\\p{L}]+),这样能匹配中文、英文、数字的话题。
内容的提问来源于stack exchange,提问作者Nishant Chandwani
相关产品推荐
相关产品推荐

