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

iOS选择、复制、剪切、粘贴菜单自定义实现咨询

自定义文本选中后的Popover菜单实现方案

当然可以修改文本选中时弹出的Popover菜单,textViewSelectionChanged仅用于监听选中范围变化,无法直接替换系统菜单,需要通过系统提供的菜单交互API来实现自定义。

iOS 13+ 推荐实现方式(基于UIEditMenuInteraction)

这是苹果在iOS 13之后推出的更灵活的菜单自定义方案:

  • 给目标UITextView添加编辑菜单交互:
let editMenuInteraction = UIEditMenuInteraction(delegate: self)
textView.addInteraction(editMenuInteraction)
  • 实现UIEditMenuInteractionDelegate协议,自定义菜单内容:
extension YourViewController: UIEditMenuInteractionDelegate {
    func editMenuInteraction(_ interaction: UIEditMenuInteraction, menuFor configuration: UIEditMenuConfiguration, suggestedActions: [UIMenuElement]) -> UIMenu? {
        // 创建自定义菜单项
        let customAction = UIAction(title: "我的自定义操作", image: UIImage(systemName: "square.and.pencil")) { [weak self] _ in
            guard let self = self, let selectedRange = self.textView.selectedTextRange else { return }
            let selectedText = self.textView.text(in: selectedRange)
            // 这里执行你的自定义逻辑,比如处理选中的文本
            print("选中文本:\(selectedText ?? "")")
        }
        
        // 可选:保留系统默认菜单项并添加自定义项,或者直接替换为全自定义菜单
        let finalActions = suggestedActions + [customAction]
        return UIMenu(title: "", children: finalActions)
    }
}

你可以根据需求过滤suggestedActions中的系统菜单项,或者完全替换成自定义菜单。

兼容iOS <13的实现方式(基于UIMenuController)

如果需要适配更低版本系统,可以通过子类化UITextView并重写相关方法实现:

  • 自定义UITextView子类:
class CustomTextView: UITextView {
    weak var customMenuDelegate: CustomTextViewDelegate?
    
    override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        // 控制哪些菜单项显示:保留系统操作/仅显示自定义操作
        if action == #selector(copy(_:)) || action == #selector(customAction(_:)) {
            return true
        }
        return false
    }
    
    override func target(forAction action: Selector, withSender sender: Any?) -> Any? {
        if action == #selector(customAction(_:)) {
            return customMenuDelegate
        }
        return super.target(forAction: action, withSender: sender)
    }
    
    @objc func customAction(_ sender: Any) {
        guard let selectedRange = selectedTextRange else { return }
        let selectedText = text(in: selectedRange)
        customMenuDelegate?.didTapCustomAction(with: selectedText ?? "")
    }
}

// 自定义代理协议,用于回调给ViewController
protocol CustomTextViewDelegate: AnyObject {
    func didTapCustomAction(with text: String)
}
  • 在ViewController中设置代理并处理自定义操作:
class YourViewController: UIViewController, CustomTextViewDelegate {
    override func viewDidLoad() {
        super.viewDidLoad()
        let customTextView = CustomTextView(frame: view.bounds)
        customTextView.customMenuDelegate = self
        view.addSubview(customTextView)
    }
    
    func didTapCustomAction(with text: String) {
        print("触发自定义操作,选中文本:\(text)")
    }
}

为什么textViewSelectionChanged无法实现?

textViewSelectionChanged是UITextViewDelegate中的回调,仅用于通知你选中范围发生了变化,它没有权限干预系统菜单的创建和显示流程,因此不能通过这个方法替换弹出的菜单。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 04:05:35