9

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?

rmaddy
  • 314,917
  • 42
  • 532
  • 579
user2562126
  • 269
  • 2
  • 12
  • Yes. These settings needed to be in place in order for the links to work prior to ios11. I believe it is a change introduced in ios11 that has caused the UITextView to no longer record interactions with URLs; the text is selectable. – user2562126 Sep 10 '17 at 18:41
  • The problem appears to be with with the `UITextViewDelegate`. The `UITableViewCell` is set as the delegate which was fine, but no longer seems to work. I tested this by implementing `func textViewDidBeginEditing(_ textView: UITextView)` within the cell and I am finding it isn't being called just as the interactwithURL isn't. If I set the `ViewController` as the delegate then the function is called within the `ViewController`. – user2562126 Sep 10 '17 at 20:28
  • The delegate is supposed to be the `UITableViewCell`. The delegate is set within `override init(style: UITableViewCellStyle, reuseIdentifier: String?)` – user2562126 Sep 10 '17 at 20:54
  • 1
    I managed to get this working by implementing `interactwithURL` in the `ViewController` as opposed to the `UITableViewCell` by setting `ViewController` as the cell's `UITextViewDelegate`. Happy to hear any other more elegant approaches. Thanks for your help Matt. On a separate note, I have noticed that links need bit more of a firmer press to register than previously needed in ios10. – user2562126 Sep 10 '17 at 21:13
  • You should answer your own question; that is legal and encouraged, and your answer may be useful to others. In 48 hours you can (and should) accept your own answer. — I wonder whether something is coming along and making the cell _not_ be the delegate after you have set it. – matt Sep 10 '17 at 21:51
  • This problem seems to be fixed in iOS 11.2+ – user102008 May 09 '18 at 21:39

2 Answers2

3

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.

user2562126
  • 269
  • 2
  • 12
1

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.

Cœur
  • 37,241
  • 25
  • 195
  • 267