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:
- 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)
}
}
- 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)
}
}
}
- 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!