Search code examples
iosswiftuitextviewnsattributedstring

Trigger hyper link text click and and normal text click in UITextView


Hi I am trying to trigger separate click events for hyper link click and normal text click in UITextView

How to Separate hyperlink text click and and normal text click in UITextView

Hope you understand my problem.

Here is what I tried.

     override func viewDidLoad() {
        super.viewDidLoad()
        let atributedHtmlText = """
            Hey I dont have hyper link text so trigger func A(). Click <a href="http://www.google.com">I have hyper link so trigger func b here</a> for more information.
            """
        testTV.setAttributedHtmlText(atributedHtmlText)

        let tap = UITapGestureRecognizer(target: self, action: #selector(ViewController.tapFunction))
        testTV.isUserInteractionEnabled = true
        testTV.addGestureRecognizer(tap)
        testTV.delegate = self
     }

     @objc func tapFunction(sender:UITapGestureRecognizer) {
        print("tap working")
     }

     extension ViewController: UITextViewDelegate {
        func textView(_ textView: UITextView, shouldInteractWith URL: URL,
                  in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
          print("URL Text Tapped ", URL)
          return false
    }
}

Solution

  • A possible solution is to add a "fake URL" (like a "internal URL Scheme look alike) where there is no link attribute:

    attributedText.enumerateAttribute(.link, in: NSRange(location: 0, length: attributedText.length), options: []) { (attribute, range, pointee) in
        //If there is no URL => Set our custom one
        if attribute == nil {
            attributedText.addAttribute(.link, value: "com.myapp.custom", range: range)
        }
    }
    

    And in this delegate method, check the value of URL.

    func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
        print("url: \(URL)")
        if url == ... {} else { ... }
        return false
    }