UIViewRepresentable封装UITextView与SwiftUI父视图点击冲突问询
问题根因
这个冲突的本质是UIKit控件的触摸事件默认不会主动阻断SwiftUI父视图的手势响应链,UITextView识别到链接点击触发回调后,事件仍然会向上传递到父层VStack触发其绑定的点击手势。
解决方案1:UIKit层拦截事件(更稳定,推荐)
直接在封装的UITextView中添加空的点击手势,吃掉不需要向上传递的触摸事件,修改makeUIView方法的代码如下:
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 // 新增以下代码拦截点击事件 let emptyTap = UITapGestureRecognizer(target: nil, action: nil) emptyTap.cancelsTouchesInView = true // 优先级低于内置的链接识别手势,不会影响链接正常点击 textView.addGestureRecognizer(emptyTap) recalculateHeight(view: textView, result: $calculatedHeight) return textView }
这个方案不需要修改外层调用代码,所有落在TextView上的点击事件都会被拦截,不会向上传递给父视图,也完全不影响链接点击的onSelectLink回调。
解决方案2:SwiftUI层调整手势优先级
如果不想修改封装组件的内部代码,可以在调用层给TextViewWrapper添加高优先级的空点击手势,代码如下:
struct Content: View { var body: some View { VStack { TextViewWrapper(text: "Text with link https://google.com", onSelectLink: { _ in print("On select link") }) // 新增高优先级空点击手势,吃掉落在TextView上的点击事件 .highPriorityGesture(TapGesture()) } .onTapGesture { print("On tap gesture") } } }
这个方案实现更简单,适合临时修复场景。
内容的提问来源于stack exchange,提问作者José Roberto Abreu
相关产品推荐
相关产品推荐

