使用SwiftUI TextEditor撤消/重做文本输入

时间:2020-10-30 16:05:03

标签: swift swiftui text-editor undo-redo nsundomanager

诚然,这是一个广泛的问题,但是使用SwiftUI TextEditor控件时是否可以撤消或重做文本输入(通过iOS的UndoManager?)?我到处都是,找不到适合该工作流程组合(SwiftUI + TextEditor + UndoManager)的任何资源。考虑到TextEditor相对不成熟,我不知道这是根本不可能的,还是需要一些管道工作来促进。任何指导将不胜感激!

1 个答案:

答案 0 :(得分:0)

关于使用 UIViewRepresentable 作为 TextView 或 TextField...。这种方法适用于撤消,但似乎不适用于重做。

重做按钮条件 undoManager.canRedo 似乎发生了适当的变化。但是,它不会将任何未完成的文本返回到文本字段或 TextView

我现在想知道这是一个错误还是我在逻辑中遗漏的东西?

 
import SwiftUI
import PlaygroundSupport

class Model: ObservableObject {
    @Published var active = ""
    
    func registerUndo(_ newValue: String, in undoManager: UndoManager?) {
        let oldValue = active
        undoManager?.registerUndo(withTarget: self) { target in
            target.active = oldValue
        }
        active = newValue
    }
}

struct TextView: UIViewRepresentable {
    
    @Binding var text: String
    
    func makeUIView(context: Context) -> UITextView {
        
        
        let textView = UITextView()
        textView.autocapitalizationType = .sentences
        textView.isSelectable = true
        textView.isUserInteractionEnabled = true
        
        return textView
    }
    
    func updateUIView(_ uiView: UITextView, context: Context) {
        uiView.text = text
    }
}


struct ContentView: View {
    
    @ObservedObject private var model = Model()
    @Environment(\.undoManager) var undoManager
    @State var text: String = ""
    
    
    var body: some View {
        ZStack (alignment: .bottomTrailing) {
            // Testing TextView for undo & redo functionality
            TextView(text: Binding<String>(
                        get: { self.model.active },
                        set: { self.model.registerUndo($0, in: self.undoManager) }))
            HStack{ 
                // Testing TextField for undo & redo functionality
                TextField("Enter Text...", text: Binding<String>(
                            get: { self.model.active },
                            set: { self.model.registerUndo($0, in: self.undoManager) })).padding()
                Button("Undo") {
                    withAnimation {
                        self.undoManager?.undo()
                    }
                }.disabled(!(undoManager?.canUndo ?? false)).padding()
                Button("Redo") {
                    withAnimation {
                        self.undoManager?.redo()
                    }
                }.disabled(!(undoManager?.canRedo ?? false)).padding()
            }.background(Color(UIColor.init(displayP3Red: 0.1, green: 0.3, blue: 0.3, alpha: 0.3)))
        }.frame(width: 400, height: 400, alignment: .center).border(Color.black)
    }
}

PlaygroundPage.current.setLiveView(ContentView())