swiftuiuitextviewtextcolor

Swiftui using UITextVIew for hyperlink but can't change text color


I am trying to use UITextView in swiftui to display a text which contains hyperlinks inside. The text and the links should be with same color except the links are underlined.

I tried to implement UITextView, but I only managed to change the link foreground color. I added textView.textColor = xxx but it didn't work. Only my links' color are changed.

    func makeUIView(context: Context) -> UITextView {
        let textView = UITextView()
    
        textView.delegate = context.coordinator
        textView.isEditable = false
        textView.font = font
        textView.autocapitalizationType = .sentences
        textView.textColor = UIColor(red: 255, green: 255, blue: 255, alpha: 0.5)
        textView.isSelectable = true
        textView.isUserInteractionEnabled = true
        textView.backgroundColor = .clear
        textView.textContainerInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
        textView.frame = textView.frame.integral
    
        return textView
    }


   func updateUIView(_ uiView: UITextView, context: Context) {
        let style = NSMutableParagraphStyle()
        let attributedOriginalText = NSMutableAttributedString(string: text)
    
        for (hyperLink, urlString) in hyperLinks {
            let linkRange = attributedOriginalText.mutableString.range(of: hyperLink)
            let fullRange = NSRange(location: 0, length: attributedOriginalText.length)
            attributedOriginalText.addAttribute(NSAttributedString.Key.link, value: urlString, range: linkRange)
            attributedOriginalText.addAttribute(NSAttributedString.Key.paragraphStyle, value: style, range: fullRange)
        }
    
        uiView.linkTextAttributes = [
            .underlineStyle : NSUnderlineStyle.single.rawValue,
            .foregroundColor: UIColor(red: 255, green: 255, blue: 255, alpha: 0.5)
        ]
    
        uiView.attributedText = attributedOriginalText
    
        // COMPUTE HEIGHT FOR CONTENT
        let width = uiView.frame.size.width
        let newSize = uiView.sizeThatFits(CGSize(width: width, height: CGFloat.greatestFiniteMagnitude))
    
        DispatchQueue.main.async {
            self.dynamicHeight = newSize.height
        }
    }

Solution

  • Here is what I meant. Tested with Xcode 13.3 / iOS 15.4

    demo

    *Red color used for better visibility

    func updateUIView(_ uiView: UITextView, context: Context) {
        let attributedOriginalText = NSMutableAttributedString(string: text)
    
        for (urlString, hyperLink) in links {
            let linkRange = attributedOriginalText.mutableString.range(of: hyperLink)
            attributedOriginalText.addAttribute(.link, value: urlString, range: linkRange)
        }
    
        let fullRange = NSRange(location: 0, length: attributedOriginalText.length)
        attributedOriginalText.addAttribute(.foregroundColor, value: UIColor.red, range: fullRange)
    
        uiView.attributedText = attributedOriginalText
        uiView.linkTextAttributes = [
            .underlineStyle : NSUnderlineStyle.single.rawValue,
            .foregroundColor: UIColor.red
        ]