I have a problem that \"boundingRectForGlyphRange\" always returns CGRect.zero \"0.0, 0.0, 0.0, 0.0\". \"boundingRectForGlyphRange\" is not working. For example, I am coding
This is a real easy alternative for anyone who is willing to use a textView. I realize this question is about a UILabel but if you read the comments on some of the answers they don't work for some people and some of them are very code heavy which isn't very good for beginners. You can do this in 11 simple steps if your willing to swap out a UILabel for a UITextView.
You can use NSMutableAttributedString
and a UITextView
. The UITextView has a delegate method: func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool { ... }
. Once you set the part of the string that you want to make tappable the delegate method will activate it.
The 11 steps are listed below in the comments above each piece of code.
// 1st **BE SURE TO INCLUDE** UITextViewDelegate to the view controller's class
class VewController: UIViewController, UITextViewDelegate {
// 2nd use a programmatic textView or use the textView from your storyboard
lazy var yourTextView: UITextView = {
let textView = UITextView()
textView.textAlignment = .center
textView.isEditable = false
textView.showsVerticalScrollIndicator = false
return textView
}()
override func viewDidLoad() {
super.viewDidLoad()
// 3rd in viewDidLoad set the textView's delegate
yourTextView.delegate = self
// 4th create the first piece of the string you don't want to be tappable
let regularText = NSMutableAttributedString(string: "any text ", attributes: [NSAttributedStringKey.font: UIFont.systemFont(ofSize: 17), NSAttributedStringKey.foregroundColor: UIColor.black])
// 5th create the second part of the string that you do want to be tappable. I used a blue color just so it can stand out.
let tappableText = NSMutableAttributedString(string: "READ MORE")
tappableText.addAttribute(NSAttributedString.Key.font, value: UIFont.systemFont(ofSize: 17), range: NSMakeRange(0, tappableText.length))
tappableText.addAttribute(NSAttributedString.Key.foregroundColor, value: UIColor.blue, range: NSMakeRange(0, tappableText.length))
// 6th this ISN'T NECESSARY but this is how you add an underline to the tappable part. I also used a blue color so it can match the tappableText and set the value to 1 for the line height. The length of the underline is based on the tappableText's length using NSMakeRange(0, tappableText.length)
tappableText.addAttribute(NSAttributedString.Key.underlineStyle, value: 1, range: NSMakeRange(0, tappableText.length))
tappableText.addAttribute(NSAttributedString.Key.underlineColor, value: UIColor.blue, range: NSMakeRange(0, tappableText.length))
// 7th this is the important part that connects the tappable link to the delegate method in step 11
// use NSAttributedString.Key.link and the value "makeMeTappable" to link the NSAttributedString.Key.link to the method. FYI "makeMeTappable" is a name I choose for clarity, you can use anything like "anythingYouCanThinkOf"
tappableText.addAttribute(NSAttributedString.Key.link, value: "makeMeTappable", range: NSMakeRange(0, tappableText.length))
// 8th *** important append the tappableText to the regularText ***
regularText.append(tappableText)
// 9th set the regularText to the textView's attributedText property
yourTextView.attributedText = regularText
}
// 10th add the textView's delegate method that activates urls. Make sure to return false for the tappable part
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool {
// 11th use the value from the 7th step to trigger the url inside this method
if URL.absoluteString == "makeMeTappable" {
// in this situation I'm using the tappableText to present a view controller but it can be used for whatever you trying to do
let someVC = SomeController()
let navVC = UINavigationController(rootViewController: someVC)
present(navVC, animated: true, completion: nil)
return false // *** IMPORTANT return false for this to actually work ***
}
return true
}
}