You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 16:27:05