I want to overlay pencil kit canvases automatically on PDFView with the new PDFKit OverlayProvider Protocol in iPad OS 16.
I added PKCanvas view as a subview of OverlayView, which is UIView, for PDFKit. I succeed in displaying and deleting overlay views based on the OverlayViewProvider protocol.
Setup the pdfview in overlay provider
The canvases are displayed as it supposed to be, however, the pencil interaction is not activated. Instead, only the PDF UI scroll view gesture is activated. Should I drop PDF views’ gestures?
PDFView for Swift UI
struct PDFKitViewRepresentable: UIViewRepresentable {
let pdfDocument: PDFDocument
let pdfView:PDFView
init(showing pdfDoc: PDFDocument, pdfView:PDFView) {
self.pdfDocument = pdfDoc
self.pdfView = pdfView
}
func makeUIView(context: Context) -> PDFView {
pdfView.displayDirection = .vertical
pdfView.displayMode = .singlePageContinuous
pdfView.usePageViewController(true)
pdfView.pageBreakMargins = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
pdfView.autoScales = false
pdfView.delegate = context.coordinator
pdfView.pageOverlayViewProvider = context.coordinator
pdfView.backgroundColor = UIColor(white: 0.04, alpha: 0.2)
return pdfView
}
func updateUIView(_ pdfView: PDFView, context: Context) {
pdfView.document = pdfDocument
}
func makeCoordinator()-> Coordinator {
Coordinator()
}
}
Coordinator code
class Coordinator: NSObject, PDFPageOverlayViewProvider, PDFViewDelegate, PDFDocumentDelegate, UIGestureRecognizerDelegate, PKCanvasViewDelegate, PKToolPickerObserver {
var pageToViewMapping = [PDFPage: CustomUIView]()
func pdfView(_ view: PDFView, overlayViewFor page: PDFPage) -> UIView? {
var resultView:CustomUIView = CustomUIView()
if let overlayView = pageToViewMapping[page] {
var canvas = overlayView.viewWithTag((Int(page.label!)!))
canvas?.becomeFirstResponder()
resultView = overlayView
} else {
let toolPicker = PKToolPicker.init()
var canvasView = PKCanvasView(frame: CGRect(x: 0, y: 0, width: 500, height: 500))
resultView.backgroundColor = UIColor.red.withAlphaComponent(0.1)
canvasView.drawingPolicy = .anyInput
canvasView.backgroundColor = .yellow.withAlphaComponent(0.2)
resultView.frame = page.bounds(for: .mediaBox)
toolPicker.addObserver(canvasView)
toolPicker.setVisible(true, forFirstResponder: canvasView)
canvasView.delegate = resultView
canvasView.becomeFirstResponder()
canvasView.tag = Int(page.label!)!
resultView.addSubview(canvasView)
pageToViewMapping[page] = resultView
}
let page = MyPDFPage(page:page)
return resultView
}
func pdfView(_ pdfView: PDFView, willDisplayOverlayView overlayView: UIView, for page: PDFPage){
// Overlay view will display
}
func pdfView(_ pdfView: PDFView, willEndDisplayingOverlayView overlayView: UIView, for page: PDFPage){
// Overlay view would be disappear
}
}
In the 2022 WWDC PDFKit video – https://developer.apple.com/videos/play/wwdc2022/10089/ – it would be achievable with less than 30 lines of code. So I use the code snippet and check the basic mechanism. But can not draw on canvas.
2
Answers
The reason why drawing gestures and scrolling gestures are having conflict was configuration of PDF View.
pdfView.displayMode = .singlePageContinuous pdfView.usePageViewController(false)
Then you should set isUserInteractionEnabled as true on overlay view install.
See PDFKit - PDFPageOverlayViewProvider with PKCanvasView is not forwarding Touch events - WWDC22 Session 10089
You need to also set
isInMarkupMode
on thePDFView
instance totrue
, so it changes how hit testing works.