0

I have a Text view thal look like this:

class StudyText: UITextView,  UITextViewDelegate {
    func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
        print(URL)

        return false
    }

    override var canBecomeFirstResponder: Bool {
        return false
    }
}

and this is the struct:

struct ClickableText: UIViewRepresentable {
    @Binding var text: NSMutableAttributedString

    func makeUIView(context: Context) -> StudyText {
        let view = StudyText()

        view.dataDetectorTypes = .all
        view.isEditable        = false
        view.isSelectable      = true
        view.delegate          = view
        view.isUserInteractionEnabled = true

        return view
    }

    func updateUIView(_ uiView: StudyText, context: Context) {
        uiView.attributedText = text

    }

}

And I am using the attributed links.

Every solution I tried doesn't make the links respond to a quick tap. immediately. It takes a bit of delay until the print statement is presented.

I tried this:

view.delaysContentTouches = false

And I tried this:

let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(tappedTextView(tapGesture:)))
self.addGestureRecognizer(tapRecognizer)


@objc func tappedTextView(tapGesture: UIGestureRecognizer) {

    let textView = tapGesture.view as! UITextView
    let tapLocation = tapGesture.location(in: textView)
    let textPosition = textView.closestPosition(to: tapLocation)
    let attr = textView.textStyling(at: textPosition!, in: .forward)!

    if let url: URL = attr[NSAttributedString.Key(rawValue: NSAttributedString.Key.link.rawValue)] as? URL {
        print("clicking here: \(url)")

    }

}

But none of them worked. It always responds with a delay How can I fix this?

Kevin
  • 1,103
  • 10
  • 33
  • When you say the links aren't tappable, do you mean there's no visual response on screen, or your `print` statement isn't called when you tap a link, or both? My guess is it has to do with the fact that UITextView is scrollable (by default). That means it'll have a pan gesture recognizer and a tap gesture recognizer, and when you touch the view it's initially unclear which gesture you're performing. If your print statement isn't getting called, then this comment probably won't help you. But if you just want a fast visual response, I think you'll have to set `isScrollEnabled = false`. – Jamie A Jun 05 '20 at 22:10
  • Hey sorry I wasn't clear enough. I meant the tap doesn't produce the print statement immediately. It takes some delay until it is presented in the console – Kevin Jun 06 '20 at 06:42

1 Answers1

3

UITextView responds to both single tap gestures (which let you follow a link) and double tap gestures (which let you select text). Immediately after you tap the link once, it's unclear whether you've completed your gesture or whether a second tap is coming. Only after a short delay with no second tap can it be sure that you were in fact doing a single tap at which point textView(_:shouldInteractWith:in:interaction:) is called.

Unfortunately there's no standard way to make UITextView allow following links without allowing text selection. You might be able to hunt through the gesture recognizers registered on the view and find the one responsible for recognizing double taps and disable it, but doing so could have unintended side effects.

Jamie A
  • 881
  • 1
  • 6
  • 14
  • 2
    The people who implemented `UITextView` (Apple) chose not to expose that recognizer, so attempting to find it could be unreliable (different device types or OS versions could be implemented differently) and as I said before, manipulating it could have unintended consequences. If you want your code to work long-term or on a wide range of devices, don't do it. That said, you could iterate over the elements of `UITextView.gestureRecognizers` looking for a `UITapGestureRecognizer` with `numberOfTapsRequired == 2`, and then set `isEnabled = NO`. It worked in my iOS 13.2.2 simulator, but YMMV. – Jamie A Jun 08 '20 at 21:50