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

macOS下SwiftUI开启Text可选时OpenURLAction失效的问题求助

解决方案

方法一:使用UITextView包装(推荐,兼容性稳定)

SwiftUI的Text组件在开启textSelection(.enabled)后,会覆盖自定义的openURL逻辑,这是当前框架的已知限制。可以通过UIViewRepresentable包装原生UITextView,实现同时支持文本选中和自定义链接处理:

struct SelectableTextView: UIViewRepresentable {
    let attributedString: AttributedString
    let onLinkTap: (URL) -> Void
    
    func makeUIView(context: Context) -> UITextView {
        let textView = UITextView()
        textView.attributedText = NSAttributedString(attributedString)
        textView.isEditable = false
        textView.isSelectable = true
        textView.delegate = context.coordinator
        textView.backgroundColor = .clear // 适配SwiftUI透明背景
        return textView
    }
    
    func updateUIView(_ uiView: UITextView, context: Context) {
        uiView.attributedText = NSAttributedString(attributedString)
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    class Coordinator: NSObject, UITextViewDelegate {
        let parent: SelectableTextView
        
        init(_ parent: SelectableTextView) {
            self.parent = parent
        }
        
        func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
            parent.onLinkTap(URL)
            return false // 阻止系统默认打开行为
        }
    }
}

// 使用示例
struct ContentView: View {
    let attributedString = try! AttributedString(markdown: "Here's the link: [link](https://example.com)")
    
    var body: some View {
        SelectableTextView(attributedString: attributedString) { url in
            print("自定义处理链接:\(url)")
            // 在这里编写你的链接处理逻辑
        }
        .frame(height: 50)
    }
}

方法二:纯SwiftUI手势结合位置检测(依赖未公开API,需谨慎)

如果不想依赖UIKit,可以给Text添加点击手势,通过内部渲染器检测点击位置对应的链接:

struct ContentView: View {
    let attributedString = try! AttributedString(markdown: "Here's the link: [link](https://example.com)")
    @State private var textRenderer: TextRenderer?
    
    var body: some View {
        Text(attributedString)
            .textSelection(.enabled)
            .background(TextRendererView(renderer: $textRenderer))
            .onTapGesture { location in
                guard let renderer = textRenderer else { return }
                let characterIndex = renderer.characterIndex(for: location)
                guard characterIndex < attributedString.characters.count else { return }
                
                let range = attributedString.rangeOfCharacter(at: characterIndex)!
                if let url = attributedString[range].link {
                    print("自定义处理链接:\(url)")
                    // 执行你的自定义逻辑
                }
            }
    }
}

// 辅助视图用于获取Text内部渲染器
struct TextRendererView: UIViewRepresentable {
    @Binding var renderer: TextRenderer?
    
    func makeUIView(context: Context) -> UIView {
        UIView()
    }
    
    func updateUIView(_ uiView: UIView, context: Context) {
        DispatchQueue.main.async {
            if let hostingView = uiView.superview?.superview as? UIHostingView<Text> {
                self.renderer = hostingView.renderer
            }
        }
    }
}

注意:方法二依赖SwiftUI未公开的TextRenderer和UIHostingView,未来版本可能失效,仅适合临时场景使用。

内容的提问来源于stack exchange,提问作者goldwalk

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 22:00:18