Hyperlink Label
Nguyen Truong Ky
Posted on April 27, 2020
Clickable Label is very popular in iOS, especially in Login, Register screen. You can easily see some text like this:
By register, I agree to Terms of Service and Private Policy
This is how I make this label.
Define your texts
Make sure the text you need to make clickable is exacly same to the full text.
let termText = "By register, I agree to ... Terms of Service and Private Policy"
let term = "Terms of Service"
let policy = "Private Policy"
Format the Label
let termLabel = UILabel()
let formattedText = String.format(strings: [term, policy],
boldFont: UIFont.boldSystemFont(ofSize: 15),
boldColor: UIColor.blue,
inString: termText,
font: UIFont.systemFont(ofSize: 15),
color: UIColor.black)
termLabel.attributedText = formattedText
termLabel.numberOfLines = 0
let tap = UITapGestureRecognizer(target: self, action: #selector(handleTermTapped))
termLabel.addGestureRecognizer(tap)
termLabel.isUserInteractionEnabled = true
termLabel.textAlignment = .center
String.format
is an extension from my code collection. This is the full function.
extension String {
static func format(strings: [String],
boldFont: UIFont = UIFont.boldSystemFont(ofSize: 14),
boldColor: UIColor = UIColor.blue,
inString string: String,
font: UIFont = UIFont.systemFont(ofSize: 14),
color: UIColor = UIColor.black) -> NSAttributedString {
let attributedString =
NSMutableAttributedString(string: string,
attributes: [
NSAttributedStringKey.font: font,
NSAttributedStringKey.foregroundColor: color])
let boldFontAttribute = [NSAttributedStringKey.font: boldFont, NSAttributedStringKey.foregroundColor: boldColor]
for bold in strings {
attributedString.addAttributes(boldFontAttribute, range: (string as NSString).range(of: bold))
}
return attributedString
}
}
Handle Label Tap Gesture
I get the tap location in the Label and check if this location belongs to term or policy text range.
@objc func handleTermTapped(gesture: UITapGestureRecognizer) {
let termString = termText as NSString
let termRange = termString.range(of: term)
let policyRange = termString.range(of: policy)
let tapLocation = gesture.location(in: termLabel)
let index = termLabel.indexOfAttributedTextCharacterAtPoint(point: tapLocation)
if checkRange(termRange, contain: index) == true {
handleViewTermOfUse()
return
}
if checkRange(policyRange, contain: index) {
handleViewPrivacy()
return
}
}
Supported code
- Check if a range contain an index
func checkRange(_ range: NSRange, contain index: Int) -> Bool {
return index > range.location && index < range.location + range.length
}
- Get index from a point in UILabel
extension UILabel {
func indexOfAttributedTextCharacterAtPoint(point: CGPoint) -> Int {
assert(self.attributedText != nil, "This method is developed for attributed string")
let textStorage = NSTextStorage(attributedString: self.attributedText!)
let layoutManager = NSLayoutManager()
textStorage.addLayoutManager(layoutManager)
let textContainer = NSTextContainer(size: self.frame.size)
textContainer.lineFragmentPadding = 0
textContainer.maximumNumberOfLines = self.numberOfLines
textContainer.lineBreakMode = self.lineBreakMode
layoutManager.addTextContainer(textContainer)
let index = layoutManager.characterIndex(for: point, in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
return index
}
}
Demo
And result is:
You can download the source code here
Conclusion
You can make a custom UILabel to be easier to reuse. I leave that for you. If you have any issues with this, let me know.
Enjoy coding.
Posted on April 27, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.