iOS(Swift 5):如何编程检测文本菜单操作及获取选中内容
监听UITextView文本菜单操作并获取选中内容(Swift实现)
核心思路
通过替换系统默认文本菜单的操作绑定,自定义响应逻辑来捕获点击时机,同时在响应方法中直接获取当前选中的文本内容。
实现步骤
1. 自定义UITextView子类
创建子类重写canPerformAction(_:withSender:)方法,筛选需要监听的系统操作,替换为自定义响应逻辑:
import UIKit class TrackableTextView: UITextView { // 操作回调,传递操作类型和选中内容 var menuActionCallback: ((String, String?) -> Void)? override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool { // 定义需要监听的系统操作Selector let trackedActions: [Selector] = [ #selector(copy(_:)), #selector(cut(_:)), #selector(selectAll(_:)), Selector(("_translate:")) ] if trackedActions.contains(action) { // 隐藏默认菜单,替换为自定义响应 UIMenuController.shared.setMenuVisible(false, animated: false) let actionTitle = UIMenuController.shared.menuItems?.first { $0.action == action }?.title ?? "" let customAction = UIAction(title: actionTitle) { [weak self] _ in guard let self = self else { return } let selectedText = self.selectedTextRange.flatMap { self.text(in: $0) } var actionType = "" switch action { case #selector(copy(_:)): actionType = "copy" super.copy(sender) // 保留系统默认复制行为 case #selector(cut(_:)): actionType = "cut" super.cut(sender) // 保留系统默认剪切行为 case #selector(selectAll(_:)): actionType = "select all" super.selectAll(sender) // 保留系统默认全选行为 case Selector(("_translate:")): actionType = "translate" // 系统翻译为私有API,若需保留原功能需调用私有方法,注意审核风险 default: break } self.menuActionCallback?(actionType, selectedText) } let customMenuItem = UIMenuItem(title: customAction.title, action: action) UIMenuController.shared.menuItems = [customMenuItem] UIMenuController.shared.setMenuVisible(true, animated: true) return false } return super.canPerformAction(action, withSender: sender) } // 单独处理"Look Up"操作(对应系统私有Selector _define:) override func _define(_ sender: Any?) { let selectedText = selectedTextRange.flatMap { text(in: $0) } menuActionCallback?("look up", selectedText) super._define(sender) // 保留系统默认查询行为 } }
2. 在ViewController中使用并监听回调
初始化自定义TextView,设置回调处理操作事件:
class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let textView = TrackableTextView(frame: view.bounds.inset(by: UIEdgeInsets(top: 100, left: 20, bottom: 100, right: 20))) textView.text = "测试文本,用于监听copy、cut、translate等菜单操作" textView.font = .systemFont(ofSize: 16) textView.backgroundColor = .white // 监听菜单操作回调 textView.menuActionCallback = { actionType, selectedContent in print("操作类型:\(actionType),选中内容:\(selectedContent ?? "无")") // 此处可添加日志上报、业务逻辑处理等操作 } view.addSubview(textView) } }
注意事项
- 系统
translate和look up对应的Selector为私有API,使用时需注意App Store审核风险;若要规避风险,可完全自定义文本菜单,不依赖系统私有方法。 - 自定义响应逻辑中必须手动调用
super对应的方法,否则会丢失系统默认的菜单功能。 - 全选操作的回调中,
selectedText为操作前的选中内容;若需获取全选后的内容,可延迟执行获取逻辑(如使用DispatchQueue.main.async)。
内容的提问来源于stack exchange,提问作者user8460166
相关产品推荐
相关产品推荐

