Undo/redo text input w/ SwiftUI TextEditor

Admittedly, this is a bit of a hack and non very SwiftUI-y, but it does work. Basically declare a binding in your UITextView:UIViewRepresentable to an UndoManager. Your UIViewRepresentable will set that binding to the UndoManager provided by the UITextView. Then your parent View has access to the internal UndoManager. Here’s some sample code. Redo works as well although not shown here.

struct MyTextView: UIViewRepresentable {

    /// The underlying UITextView. This is a binding so that a parent view can access it. You do not assign this value. It is created automatically.
    @Binding var undoManager: UndoManager?

    func makeUIView(context: Context) -> UITextView {
        let uiTextView = UITextView()

        // Expose the UndoManager to the caller. This is performed asynchronously to avoid modifying the view at an inappropriate time.
        DispatchQueue.main.async {
            undoManager = uiTextView.undoManager
        }

        return uiTextView
    }

    func updateUIView(_ uiView: UITextView, context: Context) {
    }

}

struct ContentView: View {

    /// The underlying UndoManager. Even though it looks like we are creating one here, ultimately, MyTextView will set it to its internal UndoManager.
    @State private var undoManager: UndoManager? = UndoManager()

    var body: some View {
        NavigationView {
            MyTextView(undoManager: $undoManager)
            .toolbar {
                ToolbarItemGroup(placement: .navigationBarTrailing) {
                    Button {
                        undoManager?.undo()
                    } label: {
                        Image(systemName: "arrow.uturn.left.circle")
                    }
                    Button {
                        undoManager?.redo()
                    } label: {
                        Image(systemName: "arrow.uturn.right.circle")
                    }
                }
            }
        }
    }
}

CLICK HERE to find out more related problems solutions.

Leave a Comment

Your email address will not be published.

Scroll to Top