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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 04:46:12