Search code examples
swiftxcodeswiftuipencilkitpkcanvasview

Select CanvasView tools over many files


I have four files. In PKCanvasRepresentation.swift I only initialise the canvas view. In CanvasView.swift I use the initialisation and want to assign the individual tools through the given selection from NoteToolbarView.swift. In NoteToolbarView I build an overview of buttons that should be used to select the tools. And finally, I merge CanvasView and NoteToolbarView into NoteView.swift. My problem is that I have not yet found a way to pass the selection from NoteToolbarView.swift to CanvasView.swift.

import SwiftUI
import PencilKit

struct PKCanvasRepresentation: UIViewRepresentable {
    @Binding var canvasView: PKCanvasView
    
    func makeUIView(context: Context) -> PKCanvasView {
        canvasView.isOpaque = false
        canvasView.tool = PKInkingTool(.pen, color: .black, width: 5)
        canvasView.drawingPolicy = .anyInput

        return canvasView
    }
    func updateUIView(_ uiView: PKCanvasView, context: Context) {
        
    }
    }
import SwiftUI
import PencilKit

struct CanvasView: View {
    @State private var canvasView = PKCanvasView()
    @Binding private var selectedTool: String
    
    public init(selectedTool: Binding<String>) {
            self._selectedTool = selectedTool
        }
   
    var body: some View {
        ZStack {
            Color.white
            PKCanvasRepresentation(canvasView: $canvasView)
                .padding(.all, 20)
                .background(Color.mint)
        }
        .onAppear {
            setTool()
        }
    }
    
    func setTool() {
        switch selectedTool {
        case "pen":
            canvasView.tool = PKInkingTool(.pen, color: .black, width: 5)
        case "eraser":
            canvasView.tool = PKEraserTool(.vector)
        default :
            canvasView.tool = PKInkingTool(.pen, color: .red, width: 5)
        }
    }
}

struct CanvasView_Previews: PreviewProvider {
    static var previews: some View {
        CanvasView(selectedTool: .constant("pen"))
    }
}

import SwiftUI
import PencilKit

struct NoteToolbarView: View {
    @Environment(\.presentationMode) var presentationMode
    
    @Binding var selectedTool: String
    
    @State private var pencilPressed = false
    @State private var eraserPressed = false
    @State private var settingPressed = false
    @State private var eraserImage = "eraser"
    @State private var pencilWeight: Font.Weight = .medium
    @State private var eraserWeight: Font.Weight = .medium
    @State private var settingWeight: Font.Weight = .medium
    
    var body: some View {
       
        VStack(alignment: .leading) {
            HStack(alignment: .center) {
                Button {
                    reset(trigger: "default")
                    presentationMode.wrappedValue.dismiss()
                    
                } label: {
                    Image(systemName: "arrowshape.turn.up.left")
                }
                Button(action: {
                    if pencilPressed {
                        PencilSecondPressed()
                        
                    } else {
                        PencilFirstPressed()
                       reset(trigger: "pencil")
                        selectedTool = "pen"
              
                    }
                }) {
                    Image(systemName: "applepencil")
                        .fontWeight(pencilWeight)
                }
                Button(action: {
                    if eraserPressed {
                        PencilSecondPressed()
                    } else {
                        PencilFirstPressed()
                        reset(trigger: "eraser")
                        selectedTool = "eraser"
                    }
                }) {
                    Image(systemName: eraserImage)
                        .fontWeight(eraserWeight)
                }
               
                Text("Notes")
                    .frame(maxWidth: .infinity, alignment: .center)
                
                Button(action: {
                    if settingPressed {
                        PencilSecondPressed()
                    } else {
                        PencilFirstPressed()
                        reset(trigger: "setting")
                    }
                }) {
                    Image(systemName: "doc.badge.plus")
                        .fontWeight(settingWeight)
                        .frame( alignment: .trailing)
                }
                Button(action: {
                    if settingPressed {
                        PencilSecondPressed()
                    } else {
                        PencilFirstPressed()
                        reset(trigger: "setting")
                    }
                }) {
                    Image(systemName: "list.dash")
                        .fontWeight(settingWeight)
                        .frame( alignment: .trailing)
                }
            }
            .frame(height: 40)
            .foregroundColor(Color.green)
            .padding(.leading, 30)
            .padding(.trailing, 30)
            .imageScale(.large)
            
            Divider()
        }
    }
    
    func reset(trigger: String) {
        switch trigger {
        case "pencil" :
            pencilWeight = .black
            pencilPressed = true
            eraserImage = "eraser"
            eraserWeight = .medium
            eraserPressed = false
            settingWeight = .medium
            settingPressed = false
        case "eraser" :
            pencilWeight = .medium
            pencilPressed = false
            eraserImage = "eraser.fill"
            eraserWeight = .black
            eraserPressed = true
            settingWeight = .medium
            settingPressed = false
        case "setting" :
            pencilWeight = .medium
            pencilPressed = false
            eraserImage = "eraser"
            eraserWeight = .medium
            eraserPressed = false
            settingWeight = .black
            settingPressed = true
        default:
            pencilWeight = .medium
            pencilPressed = false
            eraserImage = "eraser"
            eraserWeight = .medium
            eraserPressed = false
            settingWeight = .medium
            settingPressed = false
        }
        
    }
    
    func PencilFirstPressed() {
        print("first time")
    }
    func PencilSecondPressed() {
        print("second time")
    }
}

struct NoteToolbarView_Previews: PreviewProvider {
    static var previews: some View {
        NoteToolbarView(selectedTool: .constant("p"))
    }
}

import SwiftUI
import PencilKit

struct NoteView: View {
    @State private var selectedTool: String = "pen"
    @State private var screenWidth: CGFloat = UIScreen.main.bounds.width
    var body: some View {
            VStack {
                NoteToolbarView(selectedTool: $selectedTool) 
                    .frame(height: 40)
                CanvasView(selectedTool: $selectedTool) 
                    .frame(width: screenWidth - 60)
                    .padding(.all, 30)
            }
        }
    }


struct NoteView_Previews: PreviewProvider {
    static var previews: some View {
        NoteView()
    }
}


I have to admit that I haven't found a proper guide to the PencilKit and I haven't been in the world of Swift programming that long. I have tried a few times to help myself with ChatGpt but this did not really get me very far.


Solution

  • One had to use the update function of the PKCanvasView