swiftui - 使用 SwiftUI 实现 PencilKit 撤消功能

编辑:感谢一些反馈,我已经能够部分工作(更新代码以反射(reflect)当前更改)。

即使该应用程序似乎按预期运行,我仍然收到“正在修改状态...”警告。如何在 updateUIView 中更新 View 的绘图并使用 canvasViewDrawingDidChange 将新绘图推送到堆栈上而不导致此问题?我曾尝试将其包装在调度调用中,但这只会造成无限循环。


我正在尝试在 UIViewRepresentable (PKCanvasView) 中实现撤消功能。我有一个名为 WriterView 的父 SwiftUI View ,它包含两个按钮和 Canvas 。

这是父 View :

struct WriterView: View {
    @State var drawings: [PKDrawing] = [PKDrawing()]

    var body: some View {
        VStack(spacing: 10) {
            Button("Clear") {
                self.drawings = []
            }
            Button("Undo") {
                if !self.drawings.isEmpty {
                    self.drawings.removeLast()
                }
            }
            MyCanvas(drawings: $drawings)
        }
    }
}

下面是我如何实现我的 UIViewRepresentable:

struct MyCanvas: UIViewRepresentable {
    @Binding var drawings: [PKDrawing]

    func makeUIView(context: Context) -> PKCanvasView {
        let canvas = PKCanvasView()
        canvas.delegate = context.coordinator
        return canvas
    }

    func updateUIView(_ uiView: PKCanvasView, context: Context) {
        uiView.drawing = self.drawings.last ?? PKDrawing()
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(self._drawings)
    }

    class Coordinator: NSObject, PKCanvasViewDelegate {
        @Binding drawings: [PKDrawing]

        init(_ drawings: Binding<[PKDrawing]>) {
            self._drawings = drawings
        }

        func canvasViewDrawingDidChange(_ canvasView: PKCanvasView) {
            drawings.append(canvasView.drawing)
        }
    }
}

我收到以下错误:

[SwiftUI] Modifying state during view update, this will cause undefined behavior.

大概是我的协调员的 did change 函数引起的,但我不确定如何解决这个问题。解决这个问题的最佳方法是什么?

谢谢!

最佳答案

我终于(无意中)弄清楚了如何使用 UndoManager 来做到这一点。我仍然不确定 为什么 这行得通,因为我从来不需要调用 self.undoManager?.registerUndo()。如果您理解为什么我从来不需要注册事件,请发表评论。

这是我的工作父 View :

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)
        }
    }
}

这是我工作的 subview :

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) { }
}

这当然感觉更像是 SwiftUI 的预期方法,并且肯定比我之前所做的尝试更优雅。

https://stackoverflow.com/questions/60592875/

相关文章:

python - 在python中将类返回给自身

javascript - 使用javascript在数组中首先缺少正整数?

visual-studio-code - 有一种方法可以在 vscode 中的 ` `(重音符)内语

python - 按升序对月份名称字符串列表进行排序

firebase - 在 Firebase 云存储中加载预览时出错

swift - 将核心数据同步到 CloudKit 公共(public)数据库

java - JUnit 测试方法无法返回值

javascript - 使用 JavaScript 检测按键持续时间

session - Nuxt Apollo 具有用于基于 session 的身份验证的动态 head

javascript - YouTube 视频 API 片段标题包含 Next.js 中的特殊字符