SwiftUI PencilKit:工具栏与画布视图的工具选择传递问题
解决工具选择状态传递的方案
方案1:使用@Binding + 父视图中转(适合小型场景)
这是最直接的状态传递方式,通过父视图作为中转,将工具栏的选择同步到画布视图。
- 定义绘图工具枚举
先在共用位置(比如单独的枚举文件或NoteView中)定义工具类型:
enum DrawingTool: CaseIterable { case pencil, marker, eraser, lasso // 可按需扩展更多工具类型 }
- 修改NoteToolbarView
添加@Binding属性绑定选中的工具,点击按钮时更新该值:
struct NoteToolbarView: View { @Binding var selectedTool: DrawingTool var body: some View { HStack(spacing: 16) { ForEach(DrawingTool.allCases, id: \.self) { tool in Button { selectedTool = tool } label: { Text(tool.rawValue.capitalized) .padding(8) .background(selectedTool == tool ? Color.blue.opacity(0.2) : Color.clear) .cornerRadius(8) } } } .padding() } }
- 修改CanvasView
添加@Binding属性接收选中的工具,监听工具变化并更新PKCanvasView的绘图工具:
struct CanvasView: View { @Binding var selectedTool: DrawingTool @State private var canvasView: PKCanvasView = PKCanvasView() var body: some View { PKCanvasRepresentation(canvasView: $canvasView) .onChange(of: selectedTool) { newTool in updateCanvasTool(to: newTool) } } private func updateCanvasTool(to tool: DrawingTool) { switch tool { case .pencil: canvasView.tool = PKInkingTool(.pencil, color: .black, width: 2) case .marker: canvasView.tool = PKInkingTool(.marker, color: .red, width: 8) case .eraser: canvasView.tool = PKEraserTool(.vector) case .lasso: canvasView.tool = PKLassoTool() } } }
- 修改NoteView
在父视图中定义状态变量,传递给两个子视图:
struct NoteView: View { @State private var selectedTool: DrawingTool = .pencil var body: some View { VStack { NoteToolbarView(selectedTool: $selectedTool) CanvasView(selectedTool: $selectedTool) } } }
方案2:使用ObservableObject(适合复杂场景)
如果后续需要扩展工具的更多属性(比如颜色、线条粗细),用ObservableObject管理状态更灵活。
- 定义工具状态类
class ToolState: ObservableObject { @Published var selectedTool: DrawingTool = .pencil // 可添加其他属性,如selectedColor: Color = .black、lineWidth: CGFloat = 2等 }
- 修改NoteToolbarView
注入ToolState实例,点击按钮更新@Published属性:
struct NoteToolbarView: View { @ObservedObject var toolState: ToolState var body: some View { HStack(spacing: 16) { ForEach(DrawingTool.allCases, id: \.self) { tool in Button { toolState.selectedTool = tool } label: { Text(tool.rawValue.capitalized) .padding(8) .background(toolState.selectedTool == tool ? Color.blue.opacity(0.2) : Color.clear) .cornerRadius(8) } } } .padding() } }
- 修改CanvasView
注入ToolState实例,监听工具变化并更新画布工具:
struct CanvasView: View { @ObservedObject var toolState: ToolState @State private var canvasView: PKCanvasView = PKCanvasView() var body: some View { PKCanvasRepresentation(canvasView: $canvasView) .onChange(of: toolState.selectedTool) { newTool in updateCanvasTool(to: newTool) } } private func updateCanvasTool(to tool: DrawingTool) { switch tool { case .pencil: canvasView.tool = PKInkingTool(.pencil, color: .black, width: 2) case .marker: canvasView.tool = PKInkingTool(.marker, color: .red, width: 8) case .eraser: canvasView.tool = PKEraserTool(.vector) case .lasso: canvasView.tool = PKLassoTool() } } }
- 修改NoteView
创建ToolState实例并传递给子视图:
struct NoteView: View { @StateObject private var toolState = ToolState() var body: some View { VStack { NoteToolbarView(toolState: toolState) CanvasView(toolState: toolState) } } }
补充:PKCanvasRepresentation的正确实现
确保你的PKCanvasRepresentation能正确传递PKCanvasView实例:
struct PKCanvasRepresentation: UIViewRepresentable { @Binding var canvasView: PKCanvasView func makeUIView(context: Context) -> PKCanvasView { canvasView.drawingPolicy = .anyInput // 根据需求设置绘图策略 return canvasView } func updateUIView(_ uiView: PKCanvasView, context: Context) { // 如有需要更新的内容,在此处理 } }
内容的提问来源于stack exchange,提问作者Joschi
相关产品推荐
相关产品推荐

