0

I had a UIViewRepresentable implementation for a UITextView, to be able to display and handle links on <iOS15.

...
struct TextViewWrapper: UIViewRepresentable {
    ....
     func makeUIView(context: Context) -> UITextView {
        let textView = UITextView()
        textView.text = text
        textView.textColor = foregroundColor
        textView.font = font
        textView.backgroundColor = .white
        textView.dataDetectorTypes = .link
        textView.isEditable = false
        textView.isSelectable = true
        textView.isScrollEnabled = false
        textView.delegate = context.coordinator
        textView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
        textView.isExclusiveTouch = true
        recalculateHeight(view: textView, result: $calculatedHeight)
        return textView
    }
   ....

}

// Coordinator
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
    onSelectLink(URL)
    return false
}
...

This is used in a SwiftUI View in the following way:

struct Content: View {
    var body: some View {
        VStack {
            TextViewWrapper(text: "Text with link https://google.com", onSelectLink: { _ in print("On select link") })
        }
        .onTapGesture { print("On tap gesture") }
    }
}

Note: This is a simplified example. But the issue is that interacting with the link is calling the callback of onSelectLink, but also is allowing the onTapGesture recognizer to be executed. I'm expecting the UITextView touch to takes precedence and the onTapGesture be ignored.

  • Why do you need then `onTapGesture` over text view? Just remove it from common `VStack` and put only there where expected. – Asperi Oct 15 '21 at 18:29
  • @Asperi Just to clarify, the `VStack` is a card component (the tap modifier is to display the details), inside the VStack there are more views. I want the `TextViewWrapper` to capture the links (shouldInteractWithLinks: UITextViewDelegate) and avoid the onTapGesture to get fired, but if the user tap on the text which is not a detected link (then it could allow the tap to be handle by the card ~ onTapGesture) – José Roberto Abreu Oct 16 '21 at 00:17

1 Answers1

1

A possible solution is to add onTapGesture to TextViewWrapper and ignore it:

VStack {
    TextViewWrapper(text: "Text with link https://google.com", onSelectLink: { _ in print("On select link") })
        .onTapGesture {
            // ignore this tap
        }
}.onTapGesture {
    print("On tap gesture")
}
Phil Dukhov
  • 67,741
  • 15
  • 184
  • 220