Skip to content

Instantly share code, notes, and snippets.

@vukcevich
Forked from hamdan/MultipleTapLabel.swift
Created July 23, 2020 15:05
Show Gist options
  • Save vukcevich/788025e9f24153d2ef3e332592683ad6 to your computer and use it in GitHub Desktop.
Save vukcevich/788025e9f24153d2ef3e332592683ad6 to your computer and use it in GitHub Desktop.
Create Multiple Tappable Links in a UILabel
extension UITapGestureRecognizer {
func didTapAttributedTextInLabel(label: UILabel, targetText: String) -> Bool {
guard let attributedString = label.attributedText, let lblText = label.text else { return false }
let targetRange = (lblText as NSString).range(of: targetText)
//IMPORTANT label correct font for NSTextStorage needed
let mutableAttribString = NSMutableAttributedString(attributedString: attributedString)
mutableAttribString.addAttributes(
[NSAttributedString.Key.font: label.font ?? UIFont.smallSystemFontSize],
range: NSRange(location: 0, length: attributedString.length)
)
// Create instances of NSLayoutManager, NSTextContainer and NSTextStorage
let layoutManager = NSLayoutManager()
let textContainer = NSTextContainer(size: CGSize.zero)
let textStorage = NSTextStorage(attributedString: mutableAttribString)
// Configure layoutManager and textStorage
layoutManager.addTextContainer(textContainer)
textStorage.addLayoutManager(layoutManager)
// Configure textContainer
textContainer.lineFragmentPadding = 0.0
textContainer.lineBreakMode = label.lineBreakMode
textContainer.maximumNumberOfLines = label.numberOfLines
let labelSize = label.bounds.size
textContainer.size = labelSize
// Find the tapped character location and compare it to the specified range
let locationOfTouchInLabel = self.location(in: label)
let textBoundingBox = layoutManager.usedRect(for: textContainer)
let textContainerOffset = CGPoint(x: (labelSize.width - textBoundingBox.size.width) * 0.5 - textBoundingBox.origin.x,
y: (labelSize.height - textBoundingBox.size.height) * 0.5 - textBoundingBox.origin.y);
let locationOfTouchInTextContainer = CGPoint(x: locationOfTouchInLabel.x - textContainerOffset.x, y:
locationOfTouchInLabel.y - textContainerOffset.y);
let indexOfCharacter = layoutManager.characterIndex(for: locationOfTouchInTextContainer, in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
return NSLocationInRange(indexOfCharacter, targetRange)
}
}
//For example adding uilabel then setup
let lblPrivacyTerm = UILabel()
func setupMultipleTapLabel() {
lblPrivacyTerm.text = "By signing up you agree to our Terms of service and Privacy policy ending"
let text = (lblPrivacyTerm.text)!
let underlineAttriString = NSMutableAttributedString(string: text)
let termsRange = (text as NSString).range(of: "Terms of service")
let privacyRange = (text as NSString).range(of: "Privacy policy")
underlineAttriString.addAttribute(.foregroundColor, value: UIColor.blue, range: termsRange)
underlineAttriString.addAttribute(NSAttributedString.Key.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: privacyRange)
lblPrivacyTerm.attributedText = underlineAttriString
let tapAction = UITapGestureRecognizer(target: self, action: #selector(self.tapLabel(gesture:)))
lblPrivacyTerm.isUserInteractionEnabled = true
lblPrivacyTerm.addGestureRecognizer(tapAction)
}
@IBAction func tapLabel(gesture: UITapGestureRecognizer) {
if gesture.didTapAttributedTextInLabel(label: lblPrivacyTerm, targetText: "Terms of service") {
print("Terms of service")
} else if gesture.didTapAttributedTextInLabel(label: lblPrivacyTerm, targetText: "Privacy policy") {
print("Privacy policy")
} else {
print("Tapped none")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment