ios – Pencil Device Picker not robotically showing in SwiftUI with PencilKit

ios – Pencil Device Picker not robotically showing in SwiftUI with PencilKit


I’m at the moment engaged on a SwiftUI mission the place I exploit PencilKit for drawing on a canvas. I’m making an attempt to robotically show the Pencil Device Picker when the consumer begins drawing with the Apple Pencil, however the Device Picker doesn’t seem robotically as anticipated.

Listed here are the important thing code sections I’m utilizing:

  1. NotesView (foremost view):

I’ve a ZStack the place I render a PKCanvasRepresentable and a few Sticky Notes. I try and set off the Device Picker when the consumer drags on the canvas with the Pencil.

import PencilKit

struct NotesView: View {
    @StateObject non-public var viewModel = CanvasViewModel()
    @State non-public var stickyNotes: [StickyNoteProperties] = [] 
    @State non-public var selectedColor: Shade = .yellow 
    @State non-public var selectedNoteID: UUID? = nil 

    var physique: some View {
        VStack {
            ToolPickerView(
                isToolPickerVisible: $viewModel.isToolPickerVisible,
                toggleToolPicker: viewModel.toggleToolPicker,
                createStickyNote: createStickyNote,
                addShape: { /* Add form logic */ },
                addTextField: { /* Add textual content discipline logic */ },
                addPhoto: { /* Add picture logic */ },
                undoLastAction: viewModel.undoLastAction
            )

            ZStack {
                PKCanvasRepresentable(
                    canvasView: $viewModel.canvasView,
                    toolPicker: $viewModel.toolPicker,
                    isToolPickerVisible: $viewModel.isToolPickerVisible
                )
                .onAppear {
                    viewModel.setupCanvas()
                }
                .gesture(DragGesture(minimumDistance: 0).onChanged { _ in
                    if !viewModel.isToolPickerVisible {
                        viewModel.isToolPickerVisible = true
                        viewModel.canvasView.becomeFirstResponder()
                    }
                })

                Shade.clear
                    .contentShape(Rectangle())
                    .onTapGesture {
                        selectedNoteID = nil 
                    }

                ForEach(stickyNotes.indices, id: .self) { index in
                    StickyNoteView(stickyNote: $stickyNotes[index], selectedNoteID: $selectedNoteID)
                        .onTapGesture {
                            selectedNoteID = stickyNotes[index].id 
                        }
                }
            }
        }
        .padding()
    }

    func createStickyNote() {
        let newStickyNote = StickyNoteProperties(shade: selectedColor, measurement: CGSize(width: 200, top: 200), textual content: "") 
        stickyNotes.append(newStickyNote) 
    }
}
  1. PKCanvasRepresentable:

On this part, I arrange the PKCanvasView and attempt to activate the Device Picker via toolPicker.setVisible(true, forFirstResponder: newCanvasView) when the canvas is loaded.

import PencilKit

struct PKCanvasRepresentable: UIViewRepresentable {
    @Binding var canvasView: PKCanvasView
    @Binding var toolPicker: PKToolPicker
    @Binding var isToolPickerVisible: Bool

    func makeUIView(context: Context) -> PKCanvasView {
        let newCanvasView = canvasView
        newCanvasView.instrument = PKInkingTool(.pen, shade: .black, width: 5) 
        newCanvasView.alwaysBounceVertical = true
        newCanvasView.drawingPolicy = .pencilOnly 
        
        toolPicker.addObserver(newCanvasView)
        toolPicker.setVisible(isToolPickerVisible, forFirstResponder: newCanvasView)
        newCanvasView.becomeFirstResponder()

        return newCanvasView
    }

    func updateUIView(_ uiView: PKCanvasView, context: Context) {
        if isToolPickerVisible {
            toolPicker.setVisible(true, forFirstResponder: uiView)
            uiView.becomeFirstResponder()
        } else {
            toolPicker.setVisible(false, forFirstResponder: uiView)
        }
    }
}
  1. CanvasViewModel:

That is the ViewModel that manages the PKCanvasView and PKToolPicker. I exploit toolPicker.setVisible(…) and add the canvas as an observer.

import PencilKit

class CanvasViewModel: ObservableObject {
    @Revealed var canvasView = PKCanvasView()
    @Revealed var toolPicker = PKToolPicker()
    @Revealed var isToolPickerVisible = false

    func toggleToolPicker() {
        isToolPickerVisible.toggle()
        toolPicker.setVisible(isToolPickerVisible, forFirstResponder: canvasView)
        if isToolPickerVisible {
            canvasView.becomeFirstResponder()
        }
    }

    func setupCanvas() {
        toolPicker.addObserver(canvasView)
        toolPicker.setVisible(isToolPickerVisible, forFirstResponder: canvasView)
        canvasView.becomeFirstResponder()
    }

    func undoLastAction() {
        canvasView.undoManager?.undo()
    }
}

The Device Picker solely seems after I manually toggle it, and it doesn’t present up robotically when the Apple Pencil is used for the primary time.

Any concepts on why this is perhaps taking place and the way I can get the Device Picker to point out robotically when the consumer begins drawing with the Apple Pencil? I’ve tried setting drawingPolicy to .pencilOnly and making certain the canvas is the primary responder, however nonetheless no luck.

Thanks prematurely!

Leave a Reply

Your email address will not be published. Required fields are marked *