在使用attributedText的UITextView中实现撤销/重做功能遇阻求助
UITextView attributedText 撤销/重做功能失效问题
我正尝试为自己实现的UITextView添加undo(撤销)和redo(重做)功能,当前使用的是UITextView的attributedText属性而非普通text属性。我已参照Apple官方文档中undoManager的相关方法进行调用,但始终没有效果。通过谷歌搜索也未找到相关解决方案,请问是否有人遇到过该问题、实现过相关功能或知晓解决办法?
示例代码
textView.attributedText = NSMutableAttributedString(string: "SOME TEXT") @objc func undo(_ sender: UIButton) { textView.undoManager?.undo() } @objc func redo(_ sender: UIButton) { textView.undoManager?.redo() }
解决方案
嘿,我之前也踩过这个坑!UITextView的默认undoManager不会自动记录直接赋值attributedText的操作——它只监听用户的交互式输入,或者通过replaceCharacters(in:with:)这类标准文本编辑方法发起的修改。直接给attributedText赋值属于一次性替换全量内容,系统不会把这个操作加入撤销栈。
这里有两个靠谱的解决办法:
方法一:用UITextView的标准编辑方法修改内容
别直接赋值attributedText,改用带范围的替换方法操作内容。比如要替换整个文本,可以这样写:
let fullRange = NSRange(location: 0, length: textView.attributedText.length) textView.replaceCharacters(in: fullRange, with: NSMutableAttributedString(string: "SOME TEXT"))
这样系统的undoManager会自动把这个操作加入撤销栈,之后调用undo()和redo()就能正常工作了。
方法二:手动注册撤销/重做操作
如果必须直接赋值attributedText,那你需要手动把修改操作注册到undoManager里,步骤如下:
- 先记录修改前的
attributedText状态 - 修改文本内容
- 调用
undoManager的registerUndo(withTarget:handler:)方法,把恢复逻辑注册进去,同时还要注册重做逻辑,才能让redo功能生效
示例代码:
@objc func updateTextViewContent() { // 保存修改前的状态 let oldText = textView.attributedText // 新的目标文本 let newText = NSMutableAttributedString(string: "UPDATED TEXT") // 修改文本 textView.attributedText = newText // 注册撤销操作:恢复旧文本 textView.undoManager?.registerUndo(withTarget: self) { [weak self] target in guard let self = self else { return } self.textView.attributedText = oldText // 同时注册重做操作:回到新文本 self.textView.undoManager?.registerUndo(withTarget: self) { target in self.textView.attributedText = newText } } }
这样点击undo按钮会恢复到旧文本,点击redo又能切回新文本。
额外提醒
- 确认UITextView的
allowsUndo属性是true(默认就是true,但最好手动检查一下) - 用户手动编辑(打字、粘贴等)的操作,系统会自动处理撤销,但程序化修改必须按上面的方法手动处理
希望这些方法能帮你搞定问题!
内容的提问来源于stack exchange,提问作者Anters Bear
相关产品推荐
相关产品推荐

