Swifty Approach to Handling UITextViews With Links in Cells

There’s not a lot of documentation out there on working with text views inside of table view or collection view cells. Let’s say that we have a UITextView that has link detection and maybe even has attributed text that contains links as well. And this text view is inside of a table view cell which segues to a detail view controller when tapped (using didSelectRow.) Unfortunately at this point, you’ll notice that when you tap on your text view, the cell doesn’t register the tap and doesn’t call didSelectRow. Well then all you have to do is set textView.isUserInteractionEnabled = false. But now you can’t tap on the links in your text view! Have no fear, I came up with a solution to this problem with a modern Swift approach:

First you need to understand that link detection in UITextViews simply adds an NSLink attribute to the text. So all we really need to do is to tell whether where the user tapped on the text view has a link attribute or not.

Since UITextView is a descendant of UIView, we can override hitTest:withEvent: and get the location of the user’s tap on the text view. Then, using TextKit, we can get the character in the text view where the tap’s CGPoint is. Now this is where it gets fun — if the character is part of a link (it has an NSLink attribute), then we return self, meaning we’re telling hitTest:withEvent: to return the UITextView as the UIView that handles the event, and then UITextView automatically handles link tapping, which we can delegate textView(_:shouldInteractWith:in:interaction:) from. But if the character is not part of a link, then we return nil, which essentially tells UITextView to not handle the “hit”. This automatically passes the “hit” on to the text view’s superview which in our case is the table view cell’s contentView, which then …drumroll please… triggers didSelectRow.

Let me know if you have any questions.