我想允许用户在PDFView中查看的iOS 11 PDFKit文档上绘图。图纸最终应嵌入PDF中。
后者我通过添加类型" ink"的PDFAnnotation解决了使用与用户绘图相对应的UIBezierPath到PDFPage。
但是,如何实际记录用户在PDFView上创建的触摸以创建这样的UIBezierPath?
我已尝试在PDFView和PDFPage上覆盖touchesBegan,但它永远不会被调用。我试过添加一个UIGestureRecognizer,但没有做任何事情。
我假设我需要事后使用PDFView实例方法convert(_ point:CGPoint,to page:PDFPage)将获得的坐标转换为适合注释的PDF坐标。
答案 0 :(得分:10)
最后,我通过创建扩展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)
}
}
注释切换按钮只运行:
pdfView.isUserInteractionEnabled = !pdfView.isUserInteractionEnabled
这确实是它的关键,因为这会禁用PDF上的滚动并使我能够接收触摸事件。
触摸事件被记录并立即转换为PDFAnnotation的方式意味着在PDF上书写时注释是可见的,并且它最终被记录到PDF中的正确位置 - 无论滚动位置如何。
确保它最终出现在右页只是类似地将页面编号的硬编码0更改为pdfView.page(for:position,nearest:true)值。
答案 1 :(得分:5)
我已经通过创建一个新的视图类(例如Annotate View)并在用户注释时置于PDFView之上来完成此任务。
此视图使用它的默认touchesBegan / touchesMoved / touchesEnded方法在手势后创建贝塞尔曲线路径。触摸结束后,我的视图会将其作为注释保存在pdf上。
注意:您需要一种方法让用户决定他们是否处于注解状态。
我的班级
streamA.pipe(streamB, {end: false}).pipe(streamC, {end: false})
我的注释视图
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)
}
}
答案 2 :(得分:3)
除了jksoegaard的出色回答外,还对像我这样的新手做了一些澄清:
这些行可以排除:
UIGraphicsBeginImageContext(CGSize(width: 800, height: 600))
和
let page = pdfView.page(for: position, nearest: true)!
您需要在函数之外声明一些全局变量:
var signingPath = UIBezierPath()
var annotationAdded : Bool?
var lastPoint : CGPoint?
var currentAnnotation : PDFAnnotation?
最后,如果要使墨水更宽且颜色更好,则需要做两件事:
a。每次看到annotation.add或currentAnnotation.add之前,都需要(根据功能需要使用annotation或currentAnnotation):
let b = PDFBorder()
b.lineWidth = { choose a pixel number here }
currentAnnotation?.border = b
currentAnnotation?.color=UIColor.{ your color of choosing }
我建议为颜色指定一个较低的alpha。结果很漂亮,并且受笔画速度的影响。例如,红色为:
UIColor(red: 255/255.0, green: 0/255.0, blue: 0/255.0, alpha: 0.1)
b。记录每一次触摸的区域都需要容纳较粗的线。代替
let rect = signingPath.bounds
尝试以10px的厚度为例:
let rect = CGRect(x:signingPath.bounds.minX-5,
y:signingPath.bounds.minY-5, width:signingPath.bounds.maxX-
signingPath.bounds.minX+10, height:signingPath.bounds.maxY-
signingPath.bounds.minY+10)
重要:touchesEnded函数还使用currentAnnotation变量。您还必须在该函数中重复rect的定义(上面的简短描述或我建议的一个),并在其中也重复currentAnnotation的定义:
currentAnnotation = PDFAnnotation(bounds: rect, forType: .ink, withProperties: nil)
如果不这样做,单击不动的水龙头会使您的应用崩溃。
我可以验证文件一旦保存,便保留了注释。保存的示例代码:
let pdfData = pdfDocument?.dataRepresentation()
let annotatedPdfUrl = URL(fileURLWithPath: "\
(NSSearchPathForDirectoriesInDomains(.documentsDirectory, .userDomainMask,
true)[0])/AnnotatedPDF.pdf")
try! pdfData!.write(to: annotatedPdfUrl)