I am wondering if it is possible to add a UITapGestureRecognizer
to an NSMutableAttributedString
.
What I am looking to do is have a "more..." object after the last word of a character-limited UITextView
. In order for the object to appear immediatley after the last word, it seems best to make the UITextView
accept attributed text (rather than plain text) and then append a blue "more..." of type NSMutableAttributedString
.
I have seen examples of people accomplishing this by adding the tap gesture to the enclosing UITextView
, but that is not sufficient as I wish for an action to occur only if they tap the "more..." at the end of the attributed string within the text view. I would like to see if there is a way to add a tap gesture directly to the attributed string.
First of all, there is no way to add a gesture recogniser to a NSMutableAttributedString
because an attributed string doesn't know anything about either its position in the screen or user touches.
The process to get an attributed string drawn in a UITextView
is controlled mainly by three classes: NSTextStorage
, NSTextContainer
and NSLayoutManager
. If you want to know a little bit more about how they work, check out this awesome tutorial.
After reading that tutorial you should know that you don't need to add a tap gesture recogniser to an attributed string to get what you want. If you don't need the UITextView
to be editable, a solution would be to treat the blue More...
as a link and attach a custom action to respond when the user touches it. Here is a Swift translation of the objective-c code in this link to illustrate how to achieve that:
class ViewController: UIViewController, UITextViewDelegate {
@IBOutlet weak var textView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
let str = NSMutableAttributedString(
string: "This is a sample text that is very long but you can see it completely because More..."
)
str.addAttribute(
NSLinkAttributeName,
value: "more://",
range: (str.string as NSString).range(of: "More...")
)
textView.attributedText = str
textView.delegate = self
textView.isSelectable = true
textView.isEditable = false
}
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
if URL.scheme == "more" {
print("TODO: Handle more action here")
return false
}
else {
return true
}
}
}