Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Xcode 9 UITextView links no longer clickable

Prior to Xcode 9 and iOS 11 I had a UITextView within a UITableViewCell that contained multiple links. Each link worked as expected, however since upgrading to iOS 11 and Xcode 9, the links no longer work.

The UITextView doesn't appear to recognise any touch interaction with func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool never firing.

Has anyone else found this same problem after upgrading?

like image 993
user2562126 Avatar asked Sep 10 '17 18:09

user2562126


2 Answers

Turns out there wasn't a problem after all. Changes in the way UITextView responds to touches in iOS11 means that clicking links requires more of a press rather than just a tap which previously worked in iOS10. I think this may be something to do with the fact that in iOS11 you can now press links and drag them which also displays details of URL. So a firmer press is needed for the UITextView to register the link being tapped.

like image 73
user2562126 Avatar answered Nov 14 '22 13:11

user2562126


Specifically in iOS 11.0 and 11.1 (not later in 11.2+, not earlier in 10.x), textView(_:shouldInteractWith:in:interaction) from UITextViewDelegate is called from an interaction with a UILongPressGestureRecognizer instead of a UITapGestureRecognizer.

For those two iOS versions, user needs a small delay long press instead of a tap for a native interaction with UITextView links.

If the callback doesn't get called at all for those two iOS versions, even on a long press, you've likely been messing with gesture recognizers by subclassing your UITextView and overriding gestureRecognizerShouldBegin(_) to return false when it shouldn't.

Here is an example of quick partial workaround for gestureRecognizerShouldBegin(_) that will disable loupe/magnifier long press (if that's the desired intent of the override), but still allow long press on links:

override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
    if gestureRecognizer is UIPanGestureRecognizer {
        // required for compatibility with isScrollEnabled
        return super.gestureRecognizerShouldBegin(gestureRecognizer)
    }
    if let tapGestureRecognizer = gestureRecognizer as? UITapGestureRecognizer,
        tapGestureRecognizer.numberOfTapsRequired == 1 {
        // allowing taps for links
        return super.gestureRecognizerShouldBegin(gestureRecognizer)
    }
    if let longPressGestureRecognizer = gestureRecognizer as? UILongPressGestureRecognizer,
        // allowing small delay long press for links (required for iOS 11.0-11.1)
        // average comparison value is used to distinguish between:
        // 0.12 (smallDelayRecognizer)
        // 0.5 (textSelectionForce and textLoupe)
        longPressGestureRecognizer.minimumPressDuration < 0.325 {
        return super.gestureRecognizerShouldBegin(gestureRecognizer)
    }
    gestureRecognizer.isEnabled = false
    return false
}

An alternative is to fully disallow both UILongPressGestureRecognizer and UITapGestureRecognizer except for a self-made UITapGestureRecognizer that you would have build yourself to interact with links.

like image 1
Cœur Avatar answered Nov 14 '22 14:11

Cœur