Hi all,
I was trying to figure out how to get a UIViewRepresentable
of a PKCanvasView
to work in SwiftUI with the ability for a parent view to manage undo and redo functionality. I spent a few days of research and found a solution that seems to work well. I wanted to post this here in case this can help someone in the future!
Here's the parent view that uses the environment UndoManager:
struct Writer: View {
@Environment(\.undoManager) private var undoManager
@State private var canvasView = PKCanvasView()
var body: some View {
VStack(spacing: 10) {
Button("Clear") {
canvasView.drawing = PKDrawing()
}
Button("Undo") {
undoManager?.undo()
}
Button("Redo") {
undoManager?.redo()
}
MyCanvas(canvasView: $canvasView)
}
}
}
Here's the PKCanvasView
wrapped UIViewRepresentable
:
struct MyCanvas: UIViewRepresentable {
@Binding var canvasView: PKCanvasView
func makeUIView(context: Context) -> PKCanvasView {
canvasView.drawingPolicy = .anyInput
canvasView.tool = PKInkingTool(.pen, color: .black, width: 15)
return canvasView
}
func updateUIView(_ canvasView: PKCanvasView, context: Context) { }
}
Initially I tried various things using coordinators and PKCanvasViewDelegate
functions. In the end, the solution is very simple and straightforward. In hindsight, I feel almost foolish for how long it took me to get this working. Hopefully this will prevent a future headache for someone else!
edit: I found that my original solution broke with iOS 14. Adding canvasView.drawingPolicy = .anyInput
seemed to have fixed the problem.