You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI PencilKit:工具栏与画布视图的工具选择传递问题

解决工具选择状态传递的方案

方案1:使用@Binding + 父视图中转(适合小型场景)

这是最直接的状态传递方式,通过父视图作为中转,将工具栏的选择同步到画布视图。

  1. 定义绘图工具枚举
    先在共用位置(比如单独的枚举文件或NoteView中)定义工具类型:
enum DrawingTool: CaseIterable {
    case pencil, marker, eraser, lasso
    // 可按需扩展更多工具类型
}
  1. 修改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()
    }
}
  1. 修改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()
        }
    }
}
  1. 修改NoteView
    在父视图中定义状态变量,传递给两个子视图:
struct NoteView: View {
    @State private var selectedTool: DrawingTool = .pencil
    
    var body: some View {
        VStack {
            NoteToolbarView(selectedTool: $selectedTool)
            CanvasView(selectedTool: $selectedTool)
        }
    }
}

方案2:使用ObservableObject(适合复杂场景)

如果后续需要扩展工具的更多属性(比如颜色、线条粗细),用ObservableObject管理状态更灵活。

  1. 定义工具状态类
class ToolState: ObservableObject {
    @Published var selectedTool: DrawingTool = .pencil
    // 可添加其他属性,如selectedColor: Color = .black、lineWidth: CGFloat = 2等
}
  1. 修改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()
    }
}
  1. 修改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()
        }
    }
}
  1. 修改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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 05:29:49