I am trying to display an attributed string in a UITextview with clickable links. I've created a simple test project to see where I'm going wrong and still can't figure it out. I've tried enabling user interaction and setting the shouldInteractWithURLs delegate method, but it's still not working. Here's my code (for a view controller that only contains a textview)
  @IBOutlet weak var textView: UITextView!
override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    let string = "Google"
    let linkString = NSMutableAttributedString(string: string)
    linkString.addAttribute(NSLinkAttributeName, value: NSURL(string: "https://www.google.com")!, range: NSMakeRange(0, string.characters.count))
    linkString.addAttribute(NSFontAttributeName, value: UIFont(name: "HelveticaNeue", size: 25.0)!, range: NSMakeRange(0, string.characters.count))
    textView.attributedText = linkString
    textView.delegate = self
    textView.selectable = true
    textView.userInteractionEnabled = true
}
And here are the delegate methods I've implemented:
func textViewShouldBeginEditing(textView: UITextView) -> Bool {
    return false
}
func textView(textView: UITextView, shouldInteractWithURL URL: NSURL, inRange characterRange: NSRange) -> Bool {
    return true
}
This still isn't working. I've searched on this topic and nothing has helped yet. Thanks so much in advance.
You just set the "detect links" checkbox on the view in IB, and it detects HTTP links and turns them into hyperlinks. However, that still means that what the user sees is the "raw" link. RTF files and HTML both allow you to set up a user-readable string with a link "behind" it.
You can Change the Hyperlink Color in a TextView by the following: In the Nib file, you can go to the Properties Window and change the Tint to which ever color you want to.
Just select the UITextView in your storyboard and go to "Show Attributes inspector" and select selectable and links. As the image below shows. Make sure Editable is unchecked.

For swift3.0
  override func viewDidLoad() {
     super.viewDidLoad()
  let linkAttributes = [
        NSLinkAttributeName: NSURL(string: "http://stalwartitsolution.co.in/luminutri_flow/terms-condition")!
        ] as [String : Any]
  let attributedString = NSMutableAttributedString(string: "Please tick box to confirm you agree to our Terms & Conditions, Privacy Policy, Disclaimer. ")
  attributedString.setAttributes(linkAttributes, range: NSMakeRange(44, 18))
  attributedString.addAttribute(NSUnderlineStyleAttributeName, value: NSNumber(value: 1), range: NSMakeRange(44, 18))
  textview.delegate = self
  textview.attributedText = attributedString
  textview.linkTextAttributes = [NSForegroundColorAttributeName: UIColor.red]
  textview.textColor = UIColor.white
  }
  func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
    return true
   }
Swift 3 iOS 10: Here's Clickable extended UITextView that detect websites inside the textview automatically as long as the link start with www. for example: www.exmaple.com if it exist anywhere in the text will be clickable. Here's the class:
import Foundation
import UIKit
public class ClickableTextView:UITextView{
    var tap:UITapGestureRecognizer!
    override public init(frame: CGRect, textContainer: NSTextContainer?) {
        super.init(frame: frame, textContainer: textContainer)
        print("init")
        setup()
    }
    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }
    func setup(){
        // Add tap gesture recognizer to Text View
        tap = UITapGestureRecognizer(target: self, action: #selector(self.myMethodToHandleTap(sender:)))
        //        tap.delegate = self
        self.addGestureRecognizer(tap)
    }
    func myMethodToHandleTap(sender: UITapGestureRecognizer){
        let myTextView = sender.view as! UITextView
        let layoutManager = myTextView.layoutManager
        // location of tap in myTextView coordinates and taking the inset into account
        var location = sender.location(in: myTextView)
        location.x -= myTextView.textContainerInset.left;
        location.y -= myTextView.textContainerInset.top;
        // character index at tap location
        let characterIndex = layoutManager.characterIndex(for: location, in: myTextView.textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
        // if index is valid then do something.
        if characterIndex < myTextView.textStorage.length {
            let orgString = myTextView.attributedText.string
            //Find the WWW
            var didFind = false
            var count:Int = characterIndex
            while(count > 2 && didFind == false){
                let myRange = NSRange(location: count-1, length: 2)
                let substring = (orgString as NSString).substring(with: myRange)
//                print(substring,count)
                if substring == " w" || (substring  == "w." && count == 3){
                    didFind = true
//                    print("Did find",count)
                    var count2 = count
                    while(count2 < orgString.characters.count){
                        let myRange = NSRange(location: count2 - 1, length: 2)
                        let substring = (orgString as NSString).substring(with: myRange)
//                        print("Did 2",count2,substring)
                        count2 += 1
                        //If it was at the end of textView
                        if count2  == orgString.characters.count {
                            let length = orgString.characters.count - count
                            let myRange = NSRange(location: count, length: length)
                            let substring = (orgString as NSString).substring(with: myRange)
                            openLink(link: substring)
                            print("It's a Link",substring)
                            return
                        }
                        //If it's in the middle
                        if substring.hasSuffix(" "){
                            let length =  count2 - count
                            let myRange = NSRange(location: count, length: length)
                            let substring = (orgString as NSString).substring(with: myRange)
                            openLink(link: substring)
                            print("It's a Link",substring)
                            return
                        }
                    }
                    return
                }
                if substring.hasPrefix(" "){
                    print("Not a link")
                    return
                }
                count -= 1
            }
        }
    }
    func openLink(link:String){
        if let checkURL = URL(string: "http://\(link.replacingOccurrences(of: " ", with: ""))") {
            if UIApplication.shared.canOpenURL(checkURL) {
                UIApplication.shared.open(checkURL, options: [:], completionHandler: nil)
                print("url successfully opened")
            }
        } else {
            print("invalid url")
        }
    }
    public override func didMoveToWindow() {
        if self.window == nil{
            self.removeGestureRecognizer(tap)
            print("ClickableTextView View removed from")
        }
    }
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With