I have a UITextView which displays an NSAttributedString. This string contains words that I'd like to make tappable, such that when they are tapped I get called back so that I can perform an action. I realise that UITextView can detect taps on a URL and call back my delegate, but these aren't URLs.
It seems to me that with iOS7 and the power of TextKit this should now be possible, however I can't find any examples and I'm not sure where to start.
I understand that it's now possible to create custom attributes in the string (although I haven't done this yet), and perhaps these will be useful to detecting if one of the magic words has been tapped? In any case, I still don't know how to intercept that tap and detect on which word the tap occurred.
Note that iOS 6 compatibility is not required.
WWDC 2013 example:
This is a slightly modified version, building off of @tarmes answer. I couldn't get the
value
variable to return anything butnull
without the tweak below. Also, I needed the full attribute dictionary returned in order to determine the resulting action. I would have put this in the comments but don't appear to have the rep to do so. Apologies in advance if I have violated protocol.Specific tweak is to use
textView.textStorage
instead oftextView.attributedText
. As a still learning iOS programmer, I am not really sure why this is, but perhaps someone else can enlighten us.Specific modification in the tap handling method:
Full code in my view controller
Detecting taps on attributed text with Swift
Sometimes for beginners it is a little hard to know how to do get things set up (it was for me anyway), so this example is a little fuller.
Add a
UITextView
to your project.Outlet
Connect the
UITextView
to theViewController
with an outlet namedtextView
.Custom attribute
We are going to make a custom attribute by making an Extension.
Add a new swift file with File > New > File... > iOS > Source > Swift File. You can call it what you want. I am calling mine NSAttributedStringKey+CustomAttribute.swift.
Paste in the following code:
Code
Replace the code in ViewController.swift with the following. Note the
UIGestureRecognizerDelegate
.Now if you tap on the "w" of "Swift", you should get the following result:
Notes
NSAttributedString.Key.foregroundColor
(text color) that has a value ofUIColor.green
.Further study
This answer was based on several other answers to this question. Besides these, see also
Complete example for detect actions on attributed text with Swift 3
And then you can catch the action with
shouldInteractWith URL
UITextViewDelegate delegate method.So make sure you have set the delegate properly.Like wise you can perform any action according to your requirement.
Cheers!!
I just wanted to help others a little more. Following on from Shmidt's response it's possible to do exactly as I had asked in my original question.
1) Create an attributed string with custom attributes applied to the clickable words. eg.
2) Create a UITextView to display that string, and add a UITapGestureRecognizer to it. Then handle the tap:
So easy when you know how!
It's possible to do that with
characterIndexForPoint:inTextContainer:fractionOfDistanceBetweenInsertionPoints:
. It'll work somewhat differently than you wanted - you'll have to test if a tapped character belongs to a magic word. But it shouldn't be complicated.BTW I highly recommend watching Introducing Text Kit from WWDC 2013.