UIViewController如何拦截UITextView的复制/粘贴等编辑操作?
问题根因
你写的代码无法触发的核心逻辑是UIResponder的事件传递规则:当用户点击编辑菜单的复制/粘贴选项时,系统会将对应事件优先发送给当前的第一响应者。当UITextView处于激活编辑状态时,它本身就是第一响应者,copy:、paste:这类编辑事件会直接被UITextView实例接收处理,根本不会沿着响应链传递到上层的UIViewController,因此你在VC中重写的对应方法永远不会被调用。
另外你重写VC的canBecomeFirstResponder返回true没有实际作用——编辑操作触发时第一响应者始终是聚焦状态的UITextView,VC不会抢占第一响应者身份。
实现方案
方案1:子类化UITextView重写编辑方法(推荐,最稳定)
这是官方推荐的实现方式,不需要改动VC层的响应逻辑:
- 新建UITextView的自定义子类,重写你需要拦截的编辑方法,按需决定是否调用super保留系统默认行为
- 把项目中原来使用的UITextView替换为这个自定义子类即可,需要和VC交互的话可以通过代理、闭包把事件回调出去
示例代码:
class ActionInterceptTextView: UITextView { override func copy(_ sender: Any?) { // 写入自定义拦截逻辑 NSLog("Copy action triggered") // 需要保留系统默认复制能力就调用super,不需要就注释掉这行 super.copy(sender) } override func paste(_ sender: Any?) { NSLog("Paste action triggered") super.paste(sender) } // 可选:自定义控制编辑菜单的选项显隐 override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool { switch action { case #selector(copy(_:)), #selector(paste(_:)), #selector(cut(_:)): return true // 业务需要隐藏对应选项时返回false即可 default: return super.canPerformAction(action, withSender: sender) } } }
方案2:通过UITextViewDelegate拦截文本类操作(无需子类化)
如果只是需要拦截粘贴带来的文本修改,不需要处理复制、剪切操作,可以直接用UITextView自带的代理方法,不需要新建子类:
- 实现
textView(_:shouldChangeTextIn:replacementText:)代理方法,结合UIPasteboard的内容判断是否为粘贴触发的修改,执行自定义逻辑后返回false即可拦截默认粘贴行为,返回true则放行。 - 注意这个方案无法拦截复制、剪切这类不修改文本内容的操作,适用场景有限。
避坑提醒
不要尝试通过让textView放弃第一响应者、让VC成为第一响应者的方式实现拦截——这种方式会直接让textView失去焦点,编辑菜单会瞬间消失,根本无法触发后续的复制粘贴操作,会破坏正常的交互逻辑。
内容的提问来源于stack exchange,提问作者Deepak Sharma
相关产品推荐
相关产品推荐

