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

