How to add link inside text in iOS
By: Kirill Suslov
Tags: iOS, iOS App Development, Development, Xcode

You might have built Terms of Service page, or Privacy Notes, or Help Center screen in your Android app using the article I wrote a while ago

however you just remembered your company has also an iOS app and now you need to build the same feature there.

Here’s what we’re going to build

You might already come across other popular articles on that topic, and perhaps know two possible approaches to take:

1) UILabel

2) UITextView

Handling clicks on text with UITextView approach is a bit simple and UITextView itself has a more complex API so going UILabel way would be slightly easier.

So here’s what you gotta do:

First, add label. Use stroryboards, add views programmatically or possibly SwiftUI. Doesn’t matter.

Once you get it, you’re ready to set a text to it.

let text = "Need help? Visit the "

let link = "Help Center"

let fullText = "\(text) \(link)"

let attributedString = NSMutableAttributedString(string: fullText) label.attributedText = attributedString

You label now shows a text but it looks plain… yet. NSMutableAttributedString will allow to style text to have a link-alike look.

let linkRange = NSRange(location: text.count + 1, length: link.count) attributedString.addAttribute(

.foregroundColor,

value: UIColor.blue,

range: linkRange)

Using .foregroundColor attribute, you can color a part of the text of the label in the color you like. I calculated the range to color by splitting my original text into two pieces so it’s easy to find a beginning of the text and the length however there could be a number of ways to do that.

The last thing is to make the same part that is colored to respond on click events. UILabel doesn’t have similar to UIButton convenient click handling API so you’d need to do some extra work which is adding a gesture recognizer and setting label to be able to react on user interactions.

label.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleLabelTap)))

label.isUserInteractionEnabled = true

Adding the gesture recognizer will make the entire label react on click so here we need to write a little logic to detect if the point user touched with the finger belong to one of the characters/glyphs that are part of the text that should behave like a link. Here’s the code.

@objc func handleLabelTap(gesture: UITapGestureRecognizer) {

if gesture.state == .ended {

guard let attributedString = label1.attributedText else { return } let textStorage = NSTextStorage(attributedString: attributedString)

let layoutManager = NSLayoutManager()

textStorage.addLayoutManager(layoutManager)

let textContainer = NSTextContainer(size: label.bounds.size)

layoutManager.addTextContainer(textContainer) let location = gesture.location(in: label) let characterIndex = layoutManager.characterIndex(for: location, in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil) if characterIndex >= linkRange.location && characterIndex < linkRange.location + linkRange.length {

doWhateverYouWant()

}

}

}

NSLayoutManager here is the class that allows to access to the position of the character (with a help of two additional classes: NSTextContainer that essentially defines an area on the screen text is rendered in, and NSTextStorage that allows to hook attributedString to the layout manager). Knowing the point from the gesture we can tell if it’s one of the characters inside the range we used for the coloring link and if so, invoke a method that would perform help center action or anything else you’d need that label to do.

private func doWhateverYouWant() {

print("The link was tapped, and I can do whatever I want now!")

}

That’s it! If you need to have a working code, I have a little github repo with what I have written here (+bonus UITextView implementation of the same feature that used to work until I broke it so feel free to propose fixes if curios).

Hopefully now you can build clickable texts in both iOS and Android. Thanks for the read!