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
相关产品推荐
相关产品推荐

