I have been searching this for hours but I've failed. I probably don't even know what I should be looking for.
Many applications have text and in this text are web hyperlinks in rounded rect. When I click them UIWebView
opens. What puzzles me is that they often have custom links, for example if words starts with # it is also clickable and the application responds by opening another view. How can I do that? Is it possible with UILabel
or do I need UITextView
or something else?
In general, if we want to have a clickable link in text displayed by UILabel, we would need to resolve two independent tasks:
The first one is easy. Starting from iOS 6 UILabel supports display of attributed strings. All you need to do is to create and configure an instance of NSMutableAttributedString:
That's it! The code above makes UILabel to display String with a link
Now we should detect touches on this link. The idea is to catch all taps within UILabel and figure out whether the location of the tap was close enough to the link. To catch touches we can add tap gesture recognizer to the label. Make sure to enable userInteraction for the label, it's turned off by default:
Now the most sophisticated stuff: finding out whether the tap was on where the link is displayed and not on any other portion of the label. If we had single-lined UILabel, this task could be solved relatively easy by hardcoding the area bounds where the link is displayed, but let's solve this problem more elegantly and for general case - multiline UILabel without preliminary knowledge about the link layout.
One of the approaches is to use capabilities of Text Kit API introduced in iOS 7:
Save created and configured instances of NSLayoutManager, NSTextContainer and NSTextStorage in properties in your class (most likely UIViewController's descendant) - we'll need them in other methods.
Now, each time the label changes its frame, update textContainer's size:
And finally, detect whether the tap was exactly on the link:
(My answer builds on @NAlexN's excellent answer. I won't duplicate his detailed explanation of each step here.)
I found it most convenient and straightforward to add support for tap-able UILabel text as a category to UITapGestureRecognizer. (You don't have to use UITextView's data detectors, as some answers suggest.)
Add the following method to your UITapGestureRecognizer category:
Example Code
Gesture Callback
based on Charles Gamble answer, this what I used (I removed some lines that confused me and gave me wrong indexed) :
Here is my answer based on @Luca Davanzo's answer, override the
touchesBegan
event instead of a tap gesture:TAGS #Swift2.0
I take inspiration on - excellent - @NAlexN's answer and I decide to write by myself a wrapper of UILabel.
I also tried TTTAttributedLabel but I can't make it works.
Hope you can appreciate this code, any suggestions are welcome!
Old question but if anyone can use a
UITextView
instead of aUILabel
, then it is easy. Standard URLs, phone numbers etc will be automatically detected (and be clickable).However, if you need custom detection, that is, if you want to be able to call any custom method after a user clicks on a particular word, you need to use
NSAttributedStrings
with anNSLinkAttributeName
attribute that will point to a custom URL scheme(as opposed to having the http url scheme by default). Ray Wenderlich has it covered hereQuoting the code from the aforementioned link:
To detect those link clicks, implement this:
PS: Make sure your
UITextView
isselectable
.