I am trying to create a UITextView
with a hyperlink
so that when the user clicks on the link, they are taken to safari
to open the webpage. I have read on link detectors for a textview
but those samples always show link detection working if an actual url is present in the text (ie. www.google.com). I want it to be regular text that, when clicked, opens an associated URL. (ie. Google is the text and when clicked, opens up a url www.google.com). How can I accomplish this in iOS7/8?

- 2,783
- 3
- 23
- 44

- 3,183
- 11
- 42
- 90
-
Use `NSAttributedString` and `NSLinkgAttributeName`. – Larme Nov 16 '14 at 22:12
6 Answers
Use NSAttributedString
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:@"Google"
attributes:@{ NSLinkAttributeName: [NSURL URLWithString:@"http://www.google.com"] }];
self.textView.attributedText = attributedString;
Sure, you can set just a portion of the text to be the link. Please read more about the NSAttributedString
here.
If you want to have more control and do something before opening the link. You can set the delegate to the UITextView
.
- (void)viewDidLoad {
...
self.textView.delegate = self; // self must conform to UITextViewDelegate protocol
}
...
- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange {
// Do whatever you want here
NSLog(@"%@", URL); // URL is an instance of NSURL of the tapped link
return YES; // Return NO if you don't want iOS to open the link
}

- 2,189
- 19
- 12
-
Just a quick followup: How can I get the ability that, when tapped, I get back the url that was tapped so I can send a web request? For ex. tapping Google would activate some selector which will pass the NSURL www.google.com)? – John Baum Nov 16 '14 at 22:18
-
Set `self` (or whatever you want) to the `UITextView`'s delegate. Then implement `textView:shouldInteractWithURL:inRange:`. I'll update my answer to reflect this question. – yusuke024 Nov 16 '14 at 22:24
-
What if i want to handle the link opening myself or want to do something else with the link (such as passing it to another object to initiate a network request). Ideally, I would want to get back the url of the text i just clicked on. How can i do that? – John Baum Nov 16 '14 at 23:06
-
1In `- textView:shouldInteractWithURL:inRange:` you get the URL (an instance of `NSURL`) that was tapped. You can do anything with it. Just return `NO` in that delegate method to prevent _iOS_ from opening the link. – yusuke024 Nov 17 '14 at 01:27
-
Just in case `textView:shouldInteractWithURL:inRange:` is `deprecated` and replaced with `textView:shouldInteractWithURL:inRange:interaction:` – Bruno Bieri Dec 03 '19 at 17:29
Swift 3, iOS10 , Xcode 9
@sikhapol's answer is really nice if you knew exactly the words you want to parse like "word dictionary" somehow
it's all about the string itself that displayed in UITextView
My solution is based on the text rendering if you make the UITextView render HTML tags you may use href tag
Here is some Code references you may use
first, you need to configure UITextView from interface builder or form code to
- Selectable
- Data detectores
Note: do not make the textview editable
Interface builder
programmatically
let htmlData = NSString(string: "go to <a href=\"http://www.google.com\">google</a> and search for it").data(using: String.Encoding.unicode.rawValue)
let attributedString = try! NSAttributedString(data: htmlData!, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType], documentAttributes: nil)
yourUIViewView.isSelectable = true
yourUIViewView.dataDetectorTypes = .link
yourUIViewView.attributedText = attributedString
yourUIViewView.delegate = self
for the UITextViewDelegate
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
// check for the url string for performing your own custom actions here
let urlString = URL.absoluteString
// Return NO if you don't want iOS to open the link
return true
}

- 3,711
- 1
- 45
- 37
-
3Here's a more up-to-date way to do this: `let attributedString = try? NSAttributedString(data: Data("some cool text".utf8), options: [.documentType: NSAttributedString.DocumentType.html], documentAttributes: nil)` – Nikolay Suvandzhiev May 26 '19 at 14:08
A nifty little extension that I wrote and use (Swift 4.2, tested on iOS 12.1)
extension NSAttributedString {
func replace(placeholder: String, with hyperlink: String, url: String) -> NSAttributedString {
let mutableAttr = NSMutableAttributedString(attributedString: self)
let hyperlinkAttr = NSAttributedString(string: hyperlink, attributes: [NSAttributedString.Key.link: URL(string: url)!])
let placeholderRange = (self.string as NSString).range(of: placeholder)
mutableAttr.replaceCharacters(in: placeholderRange, with: hyperlinkAttr)
return mutableAttr
}
}
Usage:
//Set through code or through interface builder
footerText.isSelectable = true
footerText.dataDetectorTypes = .link
//Keeps the original formatting from xib or storyboard
footerText.text = "By continuing, you are indicating that you accept our @Terms@ and @Privacy@."
footerText.attributedText = footerText.attributedText?
.replace(placeholder: "@Terms@", with: "Terms and Conditions", url: AppUrl.terms)
.replace(placeholder: "@Privacy@", with: "Privacy Policy", url: AppUrl.privacy)

- 683
- 7
- 17
-
If you pass font of the textView to the extension function and add it to hyperlinkAttr, all text will have same font and size. – Ibrahim Jul 19 '19 at 05:12
-
1
-
I wanted to disable the text selection on textview as on tapping other part of string it opens selection controller which i don't want and if I set isSelectable = false then link is not clickable – Satish Mavani Apr 15 '20 at 08:34
This code sample has two different links in the same label and URL color is set to avoid the default blue.
UITextView * textTerm = [UITextView new];
NSMutableAttributedString *attrRight = [[NSMutableAttributedString alloc] initWithString:@"Terms of Service"
attributes:@{ NSLinkAttributeName: [NSURL URLWithString:@"http://www.google.com"] }];
NSMutableAttributedString *attrLeft = [[NSMutableAttributedString alloc] initWithString:@"Privacy Policy"
attributes:@{ NSLinkAttributeName: [NSURL URLWithString:@"http://www.google.com"] }];
[attrRight appendAttributedString:attrLeft];
textTerm.attributedText = attrRight;
textTerm.editable = NO;
textTerm.dataDetectorTypes = UIDataDetectorTypeAll;
textTerm.linkTextAttributes = [UIColor whiteColor];
textTerm.backgroundColor = [UIColor clearColor];

- 4,572
- 1
- 29
- 35
if you want active substring in your UITextView then you can use my extended TextView... its short and simple. You can edit it as you want.
how to use (range = substring location):
[self.textView addTapActionWithRange:range withActionBlock:^{
// anything you want to do - show something
}];
source code: https://github.com/marekmand/ActiveSubstringTextView

- 2,303
- 1
- 19
- 22
Since the edit queue was full, I'll post my version of an answer here. It's based on Amr Angry's answer.
I'm using DispatchQueue.main.async { ... } since the app will crash if the NSAttributedString is running on a background thread.
guard let htmlData = NSString(string: "go to <a href=\"http://www.google.com\">google</a> and search for it").data(using: String.Encoding.unicode.rawValue) else { return }
DispatchQueue.main.async {
do {
let attributedString = try NSAttributedString(data: htmlData, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType], documentAttributes: nil)
yourUIViewView.isSelectable = true
yourUIViewView.dataDetectorTypes = .link
yourUIViewView.attributedText = attributedString
yourUIViewView.delegate = self
} catch {
print("Cannot setup link with \(htmlData)!")
}
}
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
// Return NO if you don't want iOS to open the link
return true
}

- 423
- 5
- 12