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.
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")
}