SwiftUI TextEditor 自定义撤销按钮实现问题
SwiftUI TextEditor 自定义撤销按钮实现问题
兄弟我懂你这个困扰!SwiftUI的TextEditor自带的撤销/重做逻辑确实没直接暴露给我们开发者用,环境里拿到的UndoManager根本不是它内部实际在用的那个——毕竟底层还是依赖UITextView那套,用的是私有的_UITextUndoManager对吧?我之前也踩过这个坑,给你分享个靠谱的实现思路:
核心思路:获取TextEditor底层的UITextView实例
要拿到TextEditor真正的UndoManager,我们得先获取它包装的UITextView,然后直接用这个UITextView的undoManager属性。
步骤1:定义一个视图来捕获底层UITextView
我们可以写一个简单的UIViewRepresentable,用来在TextEditor的视图层级里找到对应的UITextView:
struct TextViewAccessor: UIViewRepresentable { let onTextViewFound: (UITextView) -> Void func makeUIView(context: Context) -> UIView { let placeholderView = UIView() // 延迟执行,确保视图层级已经构建完成 DispatchQueue.main.async { // 遍历父视图找到UITextView if let textView = placeholderView.superview?.superview? .subviews.compactMap({ $0 as? UITextView }).first { onTextViewFound(textView) } } return placeholderView } func updateUIView(_ uiView: UIView, context: Context) {} }
步骤2:在你的View中集成并保存UndoManager
在使用TextEditor的视图里,我们添加一个状态变量来保存拿到的UndoManager,然后通过background修饰符注入TextViewAccessor:
struct ContentView: View { @State private var editorText = "" @State private var textEditorUndoManager: UndoManager? var body: some View { VStack(spacing: 16) { HStack { Button("撤销") { guard let undoManager = textEditorUndoManager, undoManager.canUndo else { return } undoManager.undo() } .disabled(!(textEditorUndoManager?.canUndo ?? false)) Button("重做") { guard let undoManager = textEditorUndoManager, undoManager.canRedo else { return } undoManager.redo() } .disabled(!(textEditorUndoManager?.canRedo ?? false)) } TextEditor(text: $editorText) .background( TextViewAccessor(onTextViewFound: { textView in self.textEditorUndoManager = textView.undoManager }) ) .border(.gray, width: 1) } .padding() } }
注意事项
- 这个方法依赖于
TextEditor的底层视图层级,苹果如果在后续iOS版本中修改了视图结构,可能会失效,建议在你的目标系统版本上充分测试(亲测iOS 15-17可用) - 不要直接引用私有类
_UITextUndoManager,避免审核风险,直接用系统公开的UndoManager类型接收即可,功能完全不受影响 - 环境中的
UndoManager是SwiftUI全局环境的,和TextEditor内部的撤销逻辑完全独立,所以不能用它来实现针对TextEditor的撤销/重做
内容来源于stack exchange
相关产品推荐
相关产品推荐

