You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:46:41