I'm trying to create aUILabel
where certain words are underlined and tapping on them triggers an event. To do so I am following the top answer in this link, however I translated it to Swift : Create tap-able "links" in the NSAttributedString of a UILabel?
Here is my code :
let disclaimerLabel : TTTAttributedLabel = {
let label = TTTAttributedLabel(frame: CGRectZero)
label.textColor = UIColor.whiteColor()
label.font = UIFont.boldSystemFontOfSize(13)
label.textAlignment = .Center
label.numberOfLines = 2
label.adjustsFontSizeToFitWidth = true
return label
}()
//Inside viewDidLoad
let attString : NSMutableAttributedString = NSMutableAttributedString(string: "By logging in, you agree to our Privacy Policy and Terms and Conditions.")
let attributes : NSDictionary = [NSForegroundColorAttributeName : UIColor(red: (0.05), green: (0.4), blue: (0.65), alpha: 1.0), NSUnderlineStyleAttributeName : NSUnderlineStyle.StyleSingle.rawValue]
attString.setAttributes([NSForegroundColorAttributeName : UIColor.whiteColor()], range: NSMakeRange(0,72))
attString.setAttributes(attributes as? [String : AnyObject], range: NSMakeRange(31, 15))
attString.setAttributes(attributes as? [String : AnyObject], range: NSMakeRange(50, 21))
disclaimerLabel.setText(attString)
disclaimerLabel.userInteractionEnabled = true
disclaimerLabel.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleLabelTap)))
layoutManager = NSLayoutManager()
textContainer = NSTextContainer(size: CGSizeZero)
textStorage = NSTextStorage(attributedString: attString)
layoutManager?.addTextContainer(textContainer!)
textStorage?.addLayoutManager(layoutManager!)
textContainer!.lineFragmentPadding = 0.0
textContainer!.lineBreakMode = disclaimerLabel.lineBreakMode
textContainer!.maximumNumberOfLines = disclaimerLabel.numberOfLines
}
func handleLabelTap(tapGesture : UITapGestureRecognizer) {
let locationInLabel : CGPoint = tapGesture.locationInView(tapGesture.view)
let labelSize : CGSize = tapGesture.view!.bounds.size
let textBoundingBox : CGRect = (self.layoutManager?.usedRectForTextContainer(self.textContainer!))!
let textContainerOffset : CGPoint = CGPointMake((labelSize.width - textBoundingBox.size.width) * 0.5 - textBoundingBox.origin.x, (labelSize.height - textBoundingBox.size.height) * 0.5 - textBoundingBox.origin.y)
let locationOfTouchInTextContainer : CGPoint = CGPointMake(locationInLabel.x - textContainerOffset.x, locationInLabel.y - textContainerOffset.y)
let indexOfChar : NSInteger = (self.layoutManager?.characterIndexForPoint(locationOfTouchInTextContainer, inTextContainer: self.textContainer!, fractionOfDistanceBetweenInsertionPoints: nil))!
let rangeForPrivacy = NSMakeRange(31, 15)
let rangeForTerms = NSMakeRange(50, 21)
if (NSLocationInRange(indexOfChar, rangeForPrivacy)) {
print("privacy tapped")
self.performSegueWithIdentifier("showPrivacyPolicy", sender: self)
}
else if (NSLocationInRange(indexOfChar, rangeForTerms)) {
print("terms tapped")
}
}
Everything works fine for the first line of the label, all taps are recognised as expected, however tapping on the second line of the label (where "and conditions" is) does not trigger any event.