You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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初始化:

    1. 将canvasView.delegate = resultView改为canvasView.delegate = self(Coordinator已实现PKCanvasViewDelegate);
    2. 替换PKToolPicker.init()为PKToolPicker.shared(for: canvasView),使用共享工具选择器实例。

说明

完全禁用PDFView手势会丢失滚动、缩放等核心功能,通过调整第一响应者状态、视图适配逻辑及手势优先级,即可让PKCanvas的铅笔交互与PDFView的原生手势共存。

内容的提问来源于stack exchange,提问作者Carl.H.L

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 07:45:49