在iOS 11 PDFKit文档上实现墨迹注释

jks*_*ard 6 pdf touch ios ios11

我想允许用户在PDFView中查看iOS 11 PDFKit文档.图纸最终应嵌入PDF中.

后者我通过向PDFPage添加类型为"ink"的PDFAnnotation来解决,其中UIBezierPath对应于用户的绘图.

但是,如何实际记录用户在PDFView上创建的触摸以创建这样的UIBezierPath?

我已经尝试在PDFView和PDFPage上覆盖touchesBegan,但它永远不会被调用.我试过添加一个UIGestureRecognizer,但没有做任何事情.

我假设我需要事后使用PDFView实例方法convert(_ point:CGPoint,to page:PDFPage)将获得的坐标转换为适合注释的PDF坐标.

jks*_*ard 11

最后,我通过创建扩展UIViewController和UIGestureRecognizerDelegate的PDFViewController类解决了这个问题.我添加了一个PDFView作为子视图,并将一个UIBarButtonItem添加到navigationItem,用于切换注释模式.

我在名为signingPath的UIBezierPath中记录触摸,并使用以下代码在currentAnnotation中使用类型PDFAnnotation的当前注释:

 override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    if let touch = touches.first {
        let position = touch.location(in: pdfView)
        signingPath = UIBezierPath()
        signingPath.move(to: pdfView.convert(position, to: pdfView.page(for: position, nearest: true)!))
        annotationAdded = false
        UIGraphicsBeginImageContext(CGSize(width: 800, height: 600))
        lastPoint = pdfView.convert(position, to: pdfView.page(for: position, nearest: true)!)
    }
}

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    if let touch = touches.first {
        let position = touch.location(in: pdfView)
        let convertedPoint = pdfView.convert(position, to: pdfView.page(for: position, nearest: true)!)
        let page = pdfView.page(for: position, nearest: true)!
        signingPath.addLine(to: convertedPoint)
        let rect = signingPath.bounds

        if( annotationAdded ) {
            pdfView.document?.page(at: 0)?.removeAnnotation(currentAnnotation)
            currentAnnotation = PDFAnnotation(bounds: rect, forType: .ink, withProperties: nil)

            var signingPathCentered = UIBezierPath()
            signingPathCentered.cgPath = signingPath.cgPath
            signingPathCentered.moveCenter(to: rect.center)
            currentAnnotation.add(signingPathCentered)
            pdfView.document?.page(at: 0)?.addAnnotation(currentAnnotation)

        } else {
            lastPoint = pdfView.convert(position, to: pdfView.page(for: position, nearest: true)!)
            annotationAdded = true
            currentAnnotation = PDFAnnotation(bounds: rect, forType: .ink, withProperties: nil)
            currentAnnotation.add(signingPath)
            pdfView.document?.page(at: 0)?.addAnnotation(currentAnnotation)
        }
    }
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    if let touch = touches.first {
        let position = touch.location(in: pdfView)
        signingPath.addLine(to: pdfView.convert(position, to: pdfView.page(for: position, nearest: true)!))

        pdfView.document?.page(at: 0)?.removeAnnotation(currentAnnotation)

        let rect = signingPath.bounds
        let annotation = PDFAnnotation(bounds: rect, forType: .ink, withProperties: nil)
        annotation.color = UIColor(hex: 0x284283)
        signingPath.moveCenter(to: rect.center)
        annotation.add(signingPath)
        pdfView.document?.page(at: 0)?.addAnnotation(annotation)
    }
}
Run Code Online (Sandbox Code Playgroud)

注释切换按钮只运行:

pdfView.isUserInteractionEnabled = !pdfView.isUserInteractionEnabled
Run Code Online (Sandbox Code Playgroud)

这真的是它的关键,因为这会禁用PDF上的滚动并使我能够接收触摸事件.

记录触摸事件并立即转换为PDFAnnotation的方式意味着在PDF上书写时注释是可见的,并且最终将其记录到PDF中的正确位置 - 无论滚动位置如何.

确保它最终出现在右页只是类似地将页面编号的硬编码0更改为pdfView.page(for:position,nearest:true)值.


小智 5

我通过创建一个新的视图类(例如Annotate View)并在用户注释时放在PDFView的顶部来完成此操作.

此视图使用它的默认touchesBegan/touchesMoved/touchesEnded方法在手势后创建贝塞尔曲线路径.触摸结束后,我的视图会将其保存为pdf上的注释.

注意:您需要一种方法让用户决定他们是否处于注释状态.

对于我的主要课程

class MyViewController : UIViewController, PDFViewDelegate, VCDelegate {

var pdfView: PDFView?
var touchView: AnnotateView?

override func loadView() {
   touchView = AnnotateView(frame: CGRect(x: 0, y: 0, width: 375, height: 600))
   touchView?.backgroundColor = .clear
   touchView?.delegate = self
   view.addSubview(touchView!)
}

 func addAnnotation(_ annotation: PDFAnnotation) {
    print("Anotation added")
    pdfView?.document?.page(at: 0)?.addAnnotation(annotation)
}
}
Run Code Online (Sandbox Code Playgroud)

我的注释视图

class AnnotateView: UIView {
var path: UIBezierPath?
var delegate: VCDelegate?

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    // Initialize a new path for the user gesture
    path = UIBezierPath()
    path?.lineWidth = 4.0

    var touch: UITouch = touches.first!
    path?.move(to: touch.location(in: self))
}

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {

    // Add new points to the path
    let touch: UITouch = touches.first! 
    path?.addLine(to: touch.location(in: self))
    self.setNeedsDisplay()
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {

    let touch = touches.first 
    path?.addLine(to: touch!.location(in: self))
    self.setNeedsDisplay()
    let annotation = PDFAnnotation(bounds: self.bounds, forType: .ink, withProperties: nil)
    annotation.add(self.path!)
    delegate?.addAnnotation(annotation)
}

override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
    self.touchesEnded(touches, with: event)
}

override func draw(_ rect: CGRect) {
    // Draw the path
    path?.stroke()
}

override init(frame: CGRect) {
    super.init(frame: frame)
    self.isMultipleTouchEnabled = false
}
}
Run Code Online (Sandbox Code Playgroud)