PKCanvas莫名恢复原始绘图?技术问题求助
问题原因
你遇到的问题核心是错误地将PKCanvasView作为@State对象存储在SwiftUI视图中。PKCanvasView是UIKit的视图类,属于引用类型,而SwiftUI的@State设计用于存储值类型(如结构体、基本类型),用来管理UI状态的数据源,而非持有整个UIView实例。
当你调用load()设置canvasView.drawing = rendition后,SwiftUI的状态更新机制会触发CanvasView(UIViewRepresentable)的重新计算,但因为直接绑定了整个PKCanvasView实例,导致视图生命周期和状态不同步:后续绘制时,UIKit的画布实例和SwiftUI持有的@State实例之间出现数据不一致,最终导致绘图回退到之前的状态。
修复方案
正确的做法是让SwiftUI管理绘图数据(PKDrawing),而非UIView实例。重构代码如下:
1. 重构ContentView
将@State改为管理绘图数据,移除对PKCanvasView的持有:
struct ContentView: View { @State private var currentDrawing = PKDrawing() @State private var savedDrawing = PKDrawing() func save() { savedDrawing = currentDrawing } func load() { currentDrawing = savedDrawing } func delete() { currentDrawing = PKDrawing() } var body: some View { VStack { Button("Save") { save() } Button("Load") { load() } Button("Delete") { delete() } CanvasView(drawing: $currentDrawing) .frame(height: 400) // 给画布设置固定高度,确保可绘制区域 } .padding() } }
2. 重构CanvasView
让CanvasView接收PKDrawing的绑定,实现数据与UI的双向同步:
struct CanvasView: UIViewRepresentable { @Binding var drawing: PKDrawing @State private var toolPicker = PKToolPicker() func makeUIView(context: Context) -> PKCanvasView { let canvasView = PKCanvasView() canvasView.tool = PKInkingTool(.pen, color: .gray, width: 10) #if targetEnvironment(simulator) canvasView.drawingPolicy = .anyInput #endif canvasView.delegate = context.coordinator context.coordinator.canvasView = canvasView showToolPicker(for: canvasView) return canvasView } func updateUIView(_ uiView: PKCanvasView, context: Context) { // 当绑定的绘图数据变化时,同步更新画布内容 if uiView.drawing != drawing { uiView.drawing = drawing } } func makeCoordinator() -> Coordinator { Coordinator(drawing: $drawing) } } // MARK: - 私有方法 private extension CanvasView { func showToolPicker(for canvasView: PKCanvasView) { toolPicker.setVisible(true, forFirstResponder: canvasView) toolPicker.addObserver(canvasView) canvasView.becomeFirstResponder() } } // MARK: - Coordinator class Coordinator: NSObject, PKCanvasViewDelegate { @Binding var drawing: PKDrawing weak var canvasView: PKCanvasView? // 弱引用避免循环引用 init(drawing: Binding<PKDrawing>) { _drawing = drawing } func canvasViewDrawingDidChange(_ canvasView: PKCanvasView) { // 画布内容变化时,同步更新绑定的绘图数据 drawing = canvasView.drawing } }
关键改动说明
- 移除了对
PKCanvasView的@State和绑定,改为管理PKDrawing数据,符合SwiftUI"数据驱动UI"的设计理念。 CanvasView的updateUIView方法负责在数据变化时同步画布内容,避免状态不一致。- Coordinator通过弱引用持有
PKCanvasView,避免循环引用,同时在画布内容变化时更新绑定的drawing,确保SwiftUI状态和UIKit视图数据双向同步。
这样修改后,保存、加载、删除操作都会正确同步绘图数据,不会出现绘图回退的问题。
内容的提问来源于stack exchange,提问作者erotsppa
相关产品推荐
相关产品推荐

