iPadOS 16中PKCanvas作为PDFKit OverlayView子视图无法绘图问题
问题:PDFView叠加PKCanvas后铅笔交互失效的解决方法
问题描述
在iPadOS 16中借助PDFKit的新OverlayProvider Protocol,将PKCanvas视图作为PDFView的OverlayView子视图,已成功实现叠加视图的显示与删除,但画布的铅笔交互未激活,只有PDFView的滚动手势生效,想知道是否需要禁用PDFView的手势?
附实现代码
PDFView的SwiftUI封装代码
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() } }
协调器代码
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 } }
解决方案
无需完全禁用PDFView手势,问题核心是PKCanvasView的第一响应者状态、视图适配及手势优先级设置有误,以下是关键修正点:
适配PKCanvasView的Frame:
不要使用固定的500x500尺寸,改为匹配OverlayView的边界,并设置自动调整属性,确保画布随页面缩放:canvasView.frame = resultView.bounds canvasView.autoresizingMask = [.flexibleWidth, .flexibleHeight]正确激活第一响应者:
将激活第一响应者的逻辑移到willDisplayOverlayView方法中(此时视图已加入层级),同时关联共享的PKToolPicker:func pdfView(_ pdfView: PDFView, willDisplayOverlayView overlayView: UIView, for page: PDFPage) { if let canvasView = overlayView.subviews.first(where: { $0 is PKCanvasView }) as? PKCanvasView { canvasView.becomeFirstResponder() if let toolPicker = PKToolPicker.shared(for: canvasView) { toolPicker.setVisible(true, forFirstResponder: canvasView) toolPicker.addObserver(canvasView) } } }允许手势共存:
实现手势代理方法,允许PKCanvasView的手势与PDFView手势同时识别:func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { return otherGestureRecognizer.view is PKCanvasView }修正代理与ToolPicker初始化:
- 将
canvasView.delegate = resultView改为canvasView.delegate = self(Coordinator已实现PKCanvasViewDelegate); - 替换
PKToolPicker.init()为PKToolPicker.shared(for: canvasView),使用共享工具选择器实例。
- 将
说明
完全禁用PDFView手势会丢失滚动、缩放等核心功能,通过调整第一响应者状态、视图适配逻辑及手势优先级,即可让PKCanvas的铅笔交互与PDFView的原生手势共存。
内容的提问来源于stack exchange,提问作者Carl.H.L
相关产品推荐
相关产品推荐

