编辑:感谢一些反馈,我已经能够让这个部分工作(更新的代码来反映当前的变化)。
尽管该应用程序看起来像预期的那样工作,但我仍然得到“修改状态.”。警告。如何更新视图在updateUIView中的绘图,并在不引起此问题的情况下使用canvasViewDrawingDidChange将新的绘图推送到堆栈中?我尝试过将其封装在调度调用中,但这只是创建了一个无限循环。
我试图在UIViewRepresentable (PKCanvasView)中实现撤销功能。我有一个名为SwiftUI的父视图WriterView,它包含两个按钮和画布。
,这是父视图:
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修改状态,这将导致未定义的行为。
据推测,这是由我的协调器的更改函数引起的,但我不知道如何解决这个问题。解决这个问题的最好方法是什么?
谢谢!
发布于 2020-03-12 03:59:30
我终于(意外地)想出了如何使用UndoManager来完成这个任务。我仍然不清楚为什么会这样,因为我从来不需要打电话给self.undoManager?.registerUndo()。如果你明白我为什么不需要注册一个事件,请发表评论。
这里是我的工作父视图:
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)
}
}
},这是我的工作子视图:
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的预期方法,而且肯定比我之前所做的尝试更优雅。
发布于 2020-03-12 06:42:16
为了完整起见,如果您想显示PKToolPicker,这里是我的UIViewRepresentable。
import Foundation
import SwiftUI
import PencilKit
struct PKCanvasSwiftUIView : UIViewRepresentable {
let canvasView = PKCanvasView()
#if !targetEnvironment(macCatalyst)
let coordinator = Coordinator()
class Coordinator: NSObject, PKToolPickerObserver {
// initial values
var color = UIColor.black
var thickness = CGFloat(30)
func toolPickerSelectedToolDidChange(_ toolPicker: PKToolPicker) {
if toolPicker.selectedTool is PKInkingTool {
let tool = toolPicker.selectedTool as! PKInkingTool
self.color = tool.color
self.thickness = tool.width
}
}
func toolPickerVisibilityDidChange(_ toolPicker: PKToolPicker) {
if toolPicker.selectedTool is PKInkingTool {
let tool = toolPicker.selectedTool as! PKInkingTool
self.color = tool.color
self.thickness = tool.width
}
}
}
func makeCoordinator() -> PKCanvasSwiftUIView.Coordinator {
return Coordinator()
}
#endif
func makeUIView(context: Context) -> PKCanvasView {
canvasView.isOpaque = false
canvasView.backgroundColor = UIColor.clear
canvasView.becomeFirstResponder()
#if !targetEnvironment(macCatalyst)
if let window = UIApplication.shared.windows.filter({$0.isKeyWindow}).first,
let toolPicker = PKToolPicker.shared(for: window) {
toolPicker.addObserver(canvasView)
toolPicker.addObserver(coordinator)
toolPicker.setVisible(true, forFirstResponder: canvasView)
}
#endif
return canvasView
}
func updateUIView(_ uiView: PKCanvasView, context: Context) {
}
} 发布于 2020-03-09 02:15:55
我认为错误可能来自私有func clearCanvas()和私有func undoDrawing()。试一试,看看它是否有效:
private func clearCanvas() {
DispatchQueue.main.async {
self.drawings = [PKDrawing()]
}
}undoDrawing()也是如此。
如果它来自canvasViewDrawingDidChange,那么做同样的技巧。
https://stackoverflow.com/questions/60592875
复制相似问题