SwiftUI中如何为文本内的URL添加长按上下文菜单?
解决SwiftUI本地化文本中URL的长按自定义操作问题
直接用Text(LocalizedStringKey)虽然能自动识别并高亮URL,但确实没法给单个URL加长按菜单。你之前尝试拼接Text加contextMenu报错,是因为+操作符只接受纯Text类型,加了contextMenu的视图已经变成了some View,没法和其他Text拼接。
下面给两种可行的实现方式:
方法一:用AttributedString结合长按手势(iOS 15+)
先把本地化字符串转成AttributedString,识别出其中的URL范围,然后给Text添加长按手势,判断点击位置对应的URL,再弹出自定义菜单。
示例代码:
import SwiftUI struct URLTextWithLongPress: View { // 本地化字符串 private let localizedText = NSLocalizedString("Multiple URLs here, such as https://stackoverflow.com or https://www.google.com", comment: "") @State private var selectedURL: URL? @State private var showMenu = false var body: some View { Text(try! AttributedString(markdown: localizedText)) .onLongPressGesture { let detector = try! NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue) let matches = detector.matches(in: localizedText, range: NSRange(location: 0, length: localizedText.utf16.count)) // 可根据实际点击位置匹配对应URL,此处简化取第一个示例 if let firstMatch = matches.first, let url = firstMatch.url { selectedURL = url showMenu = true } } .contextMenu(isPresented: $showMenu) { if let url = selectedURL { Button("复制链接") { UIPasteboard.general.url = url } Button("打开链接") { UIApplication.shared.open(url) } } } } }
注意:这种方式需要自行处理点击位置与URL的对应逻辑,适合需要高度自定义交互的场景。
方法二:用UIViewRepresentable包装UITextView(更简单,原生支持)
UITextView原生支持链接的长按复制操作,还能自定义菜单,我们可以把它包装成SwiftUI视图,同时支持本地化文本:
示例代码:
import SwiftUI import UIKit struct TextViewWithURLActions: UIViewRepresentable { let localizedKey: String func makeUIView(context: Context) -> UITextView { let textView = UITextView() textView.isEditable = false textView.isSelectable = true textView.dataDetectorTypes = .link // 设置本地化文本 textView.text = NSLocalizedString(localizedKey, comment: "") // 自定义菜单(可选) let copyAction = UIMenuItem(title: "复制链接", action: #selector(textView.copyURL(_:))) UIMenuController.shared.menuItems = [copyAction] return textView } func updateUIView(_ uiView: UITextView, context: Context) { uiView.text = NSLocalizedString(localizedKey, comment: "") } } extension UITextView { @objc func copyURL(_ sender: UIMenuController) { if let selectedRange = self.selectedTextRange, let url = self.text(in: selectedRange) { UIPasteboard.general.string = url } } } // 使用示例 struct ContentView: View { var body: some View { TextViewWithURLActions(localizedKey: "Multiple URLs here, such as https://stackoverflow.com or https://www.google.com") .frame(height: 50) .padding() } }
这种方式利用UITextView的原生能力,无需自行处理URL检测和位置判断,长按URL会自动弹出包含复制的菜单,还能通过UIMenuController添加自定义操作。如果需要保持SwiftUI Text的样式,可调整UITextView的字体、颜色等属性,让它与SwiftUI Text风格一致。
内容的提问来源于stack exchange,提问作者fer0n
相关产品推荐
相关产品推荐

