Search code examples
iosswiftuitextviewnsattributedstring

Change attributed String dynamically


I have a TableViewCell in which I have a clickable textView:

let linkTextView: UITextView = {
    let v = UITextView()
    v.backgroundColor = .clear
    v.textAlignment = .left
    v.isScrollEnabled = false
    let padding = v.textContainer.lineFragmentPadding
    v.textContainerInset =  UIEdgeInsets(top: 0, left: -padding, bottom: 0, right: -padding)
    v.tintColor = .darkCustom
    v.isEditable = false
    v.isSelectable = true
    v.translatesAutoresizingMaskIntoConstraints = false
    return v
}()
let interactableText = NSMutableAttributedString(string: "Link öffnen")

In Cell I also have these two functions to style it and make it clickable:

func setupTextView(){
    interactableText.addAttributes([.underlineStyle: NSUnderlineStyle.single.rawValue,
                                    NSAttributedString.Key.font: UIFont(name: "AvenirNext-Medium", size: 15)!,
                                    NSAttributedString.Key.underlineColor: UIColor.darkCustom],
                                   range: NSRange(location: 0, length: interactableText.length))
    
    interactableText.addAttribute(NSAttributedString.Key.link,
                                  value: "https://www.google.de/?hl=de",
                                  range: NSRange(location: 0, length: interactableText.length))
}

func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool {
    self.linkTappedCallback!(URL)
    return false
}

This setup works. However it's not what I really want. I would like to be able to change the value of the link for each cell. I tried it like this in cellForRowAt:

    print(currentWish.link)
    cell.interactableText.addAttribute(NSAttributedString.Key.link,
                                       value: currentWish.link,
                                       range: NSRange(location: 0, length: cell.interactableText.length))

But when having it like this and dont set the link inside Cell the textView is no longer clickable. What am I missing here?


Solution

  • With the help of @elarcoiris I am now using this function and it works exactly the way I want it to:

    extension UITextView {
    func hyperLink(originalText: String, hyperLink: String, urlString: String) {
    
        let style = NSMutableParagraphStyle()
        style.alignment = .left
    
        let attributedOriginalText = NSMutableAttributedString(string: originalText)
        let linkRange = attributedOriginalText.mutableString.range(of: hyperLink)
        let fullRange = NSMakeRange(0, attributedOriginalText.length)
        attributedOriginalText.addAttribute(NSAttributedString.Key.link, value: urlString, range: linkRange)
        attributedOriginalText.addAttribute(NSAttributedString.Key.paragraphStyle, value: style, range: fullRange)
        attributedOriginalText.addAttribute(NSAttributedString.Key.foregroundColor, value: UIColor.darkCustom, range: fullRange)
        attributedOriginalText.addAttribute(NSAttributedString.Key.underlineColor, value: UIColor.darkCustom, range: fullRange)
        attributedOriginalText.addAttribute(NSAttributedString.Key.font, value: UIFont(name: "AvenirNext-Medium", size: 15)!, range: fullRange)
    
        self.linkTextAttributes = [
            kCTForegroundColorAttributeName: UIColor.darkCustom,
            kCTUnderlineStyleAttributeName: NSUnderlineStyle.single.rawValue,
            ] as [NSAttributedString.Key : Any]
    
        self.attributedText = attributedOriginalText
    }
    }
    

    Usage in cellForRowAt:

    let cell = tableView.dequeueReusableCell(withIdentifier: WhishCell.reuseID, for: indexPath) as! WhishCell
    
    cell.linkTextView.hyperLink(originalText: "Link öffnen", hyperLink: "Link öffnen", urlString: currentWish.link)