如何让UITextView使用视图控制器的undoManager以统一撤销栈?
统一PKCanvasView与UITextView的单一撤销栈实现
要让UITextView复用视图控制器的undoManager,核心是替换UITextView默认的只读undoManager属性——因为UITextView自身的undoManager是只读的,无法直接赋值,所以需要通过自定义子类重写该属性来实现。
步骤1:自定义UITextView子类
创建一个继承自UITextView的子类,添加属性持有外部传入的共享undoManager,并重写undoManager方法返回这个共享实例:
Swift版本:
class SharedUndoTextView: UITextView { // 弱引用避免循环引用 weak var sharedUndoManager: UndoManager? override var undoManager: UndoManager? { // 优先使用共享的undoManager, fallback到默认实现 return sharedUndoManager ?? super.undoManager } }
Objective-C版本:
// SharedUndoTextView.h #import <UIKit/UIKit.h> @interface SharedUndoTextView : UITextView @property (nonatomic, weak) NSUndoManager *sharedUndoManager; @end // SharedUndoTextView.m #import "SharedUndoTextView.h" @implementation SharedUndoTextView - (NSUndoManager *)undoManager { return self.sharedUndoManager ?: [super undoManager]; } @end
步骤2:在视图控制器中关联共享UndoManager
在你的视图控制器中,确保自身持有一个全局的undoManager,并将所有自定义UITextView的sharedUndoManager指向它:
Swift版本:
class CanvasTextViewController: UIViewController { // 懒加载全局undoManager,可自定义撤销层级 lazy var undoManager: UndoManager = { let manager = UndoManager() manager.levelsOfUndo = 20 // 设置最大撤销次数 manager.groupsByEvent = true // 合并连续操作(如快速打字) return manager }() // IBOutlet关联的自定义TextView @IBOutlet weak var textView1: SharedUndoTextView! @IBOutlet weak var textView2: SharedUndoTextView! // 你的PKCanvasView @IBOutlet weak var canvasView: PKCanvasView! override func viewDidLoad() { super.viewDidLoad() // 给所有TextView绑定共享undoManager textView1.sharedUndoManager = self.undoManager textView2.sharedUndoManager = self.undoManager // 确保PKCanvasView也使用同一个undoManager(默认已继承父视图,但显式设置更稳妥) canvasView.undoManager = self.undoManager } }
关键注意事项
- 如果使用Storyboard/XIB创建UITextView,需在界面编辑器中将控件的类改为
SharedUndoTextView,再关联IBOutlet。 - UITextView的文本变更会自动注册到共享
undoManager中,无需额外手动注册;如果有自定义文本操作,需调用undoManager.registerUndo(withTarget:handler:)手动添加撤销逻辑。 - 测试时验证撤销/重做流程:PKToolPicker的按钮应能依次撤销PKCanvasView的绘图操作和UITextView的文本修改,反之亦然,实现统一的撤销栈。
内容的提问来源于stack exchange,提问作者Hamster
相关产品推荐
相关产品推荐

