我的
swiftui
视图中有三个按钮..
当用户对 pdf 进行注释(墨水)并清除注释,然后决定再次绘制(注释)时。被清除的旧注释重新出现。我不希望旧的注释被清除后再次出现。
清除所有功能也面临同样的错误。
一旦页面注释清晰,旧的注释就不应该出现。 一旦所有注释被清除,旧注释就不会出现。
在我的另一个视图中,我使用按下按钮时的 pdf 容器显示 pdf,我调用以下函数:
清除全部:self.myLocalCoordinator?.removeAllAnnotations()
清除:self.myLocalCoordinator?.removeAnnotationsOnCurrentPage()
提交: if let base64PDF = myLocalCoordinator?.savePDFWithAnnotations() { print("PDF 签名和注释:(base64PDF)")
}
我的本地协调员?在我看来,这只是对从完成处理程序中获得的协调器类的引用。
以下是我尝试过的:
import SwiftUI
import PDFKit
import PencilKit
import UIKit
struct PDFViewContainerMulti: UIViewRepresentable {
var base64Data: String
@Binding var currentPageIndex: Int
var completionHandler: (Int, Coordinator) -> Void
let pdfView = PDFView()
// var coordinator : Coordinator
func makeUIView(context: Context) -> PDFView {
pdfView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
if let data = Data(base64Encoded: base64Data) {
if let pdfDocument = PDFDocument(data: data) {
pdfView.document = pdfDocument
pdfView.autoScales = true
//pdfView.displayMode = .singlePageContinuous
pdfView.displayMode = .singlePage
// Enable user interactions to allow annotation
//pdfView.isUserInteractionEnabled = false
let totalNumberOfPages = pdfDocument.pageCount
print("The total pages in the pdf document is : \(totalNumberOfPages)")
completionHandler(pdfDocument.pageCount,Coordinator(parent: self))
if currentPageIndex < pdfDocument.pageCount {
pdfView.go(to: pdfDocument.page(at: currentPageIndex)!)
}
// Set up gesture recognizer for drawing
let panGestureRecognizer = UIPanGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.handlePanGesture(_:)))
pdfView.addGestureRecognizer(panGestureRecognizer)
}
}
if let scrollView = pdfView.subviews.first(where: { $0 is UIScrollView }) as? UIScrollView {
scrollView.isScrollEnabled = false // Disable default scrolling
}
// context.coordinator.pdfView = pdfView
// coordinator.pdfView = context.coordinator.pdfView
PdfView().pdfView = pdfView
return pdfView
}
func updateUIView(_ pdfView: PDFView, context: Context) {
// Update the view if needed
if currentPageIndex < pdfView.document?.pageCount ?? 0 {
pdfView.go(to: pdfView.document!.page(at: currentPageIndex)!)
}
}
func makeCoordinator() -> Coordinator {
Coordinator(parent: self)
}
}
class Coordinator: NSObject, ObservableObject {
var parent: PDFViewContainerMulti
var allPathsDict: [PDFPage: [UIBezierPath]] = [:]
var shouldDraw = false
var pdfView: PDFView?
init(parent: PDFViewContainerMulti) {
self.parent = parent
self.pdfView = parent.pdfView
}
// @objc func handlePanGesture(_ gestureRecognizer: UIPanGestureRecognizer) {
// let location = gestureRecognizer.location(in: gestureRecognizer.view)
//
// if let pdfView = gestureRecognizer.view as? PDFView {
// if let currentPage = pdfView.page(for: location, nearest: true) {
// let convertedPoint = pdfView.convert(location, to: currentPage)
//
// switch gestureRecognizer.state {
// case .began:
// shouldDraw = isPointWithinDrawingArea(convertedPoint, in: currentPage, of: pdfView)
// if shouldDraw {
// var paths = allPathsDict[currentPage] ?? []
// let currentPath = UIBezierPath()
// currentPath.move(to: convertedPoint)
// paths.append(currentPath)
// allPathsDict[currentPage] = paths
//
// let annotation = PDFAnnotation(bounds: currentPage.bounds(for: pdfView.displayBox), forType: .ink, withProperties: nil)
// annotation.color = UIColor.blue.withAlphaComponent(0.9)
// annotation.add(currentPath)
// currentPage.addAnnotation(annotation)
// }
// case .changed:
// if shouldDraw {
// if let paths = allPathsDict[currentPage], let currentPath = paths.last {
// currentPath.addLine(to: convertedPoint)
//
// currentPage.annotations.forEach { currentPage.removeAnnotation($0) }
//
// let updatedAnnotation = PDFAnnotation(bounds: currentPage.bounds(for: pdfView.displayBox), forType: .ink, withProperties: nil)
// updatedAnnotation.color = UIColor.blue.withAlphaComponent(0.9)
// paths.forEach { updatedAnnotation.add($0) }
// currentPage.addAnnotation(updatedAnnotation)
//
// // savePDFWithAnnotations()
//
// }
// }
//
//
// default:
// shouldDraw = false
// break
// }
// }
// }
// }
@objc func handlePanGesture(_ gestureRecognizer: UIPanGestureRecognizer) {
let location = gestureRecognizer.location(in: gestureRecognizer.view)
if let pdfView = gestureRecognizer.view as? PDFView {
if let currentPage = pdfView.page(for: location, nearest: true) {
let convertedPoint = pdfView.convert(location, to: currentPage)
switch gestureRecognizer.state {
case .began:
shouldDraw = isPointWithinDrawingArea(convertedPoint, in: currentPage, of: pdfView)
if shouldDraw {
// Create a new path for the current annotation
var paths = allPathsDict[currentPage] ?? []
let currentPath = UIBezierPath()
currentPath.move(to: convertedPoint)
paths.append(currentPath)
allPathsDict[currentPage] = paths
// Add a new annotation
let annotation = PDFAnnotation(bounds: currentPage.bounds(for: pdfView.displayBox), forType: .ink, withProperties: nil)
annotation.color = UIColor.blue.withAlphaComponent(0.9)
annotation.add(currentPath)
currentPage.addAnnotation(annotation)
}
case .changed:
if shouldDraw {
if let paths = allPathsDict[currentPage], let currentPath = paths.last {
currentPath.addLine(to: convertedPoint)
currentPage.annotations.forEach { currentPage.removeAnnotation($0) }
let updatedAnnotation = PDFAnnotation(bounds: currentPage.bounds(for: pdfView.displayBox), forType: .ink, withProperties: nil)
updatedAnnotation.color = UIColor.blue.withAlphaComponent(0.9)
paths.forEach { updatedAnnotation.add($0) }
currentPage.addAnnotation(updatedAnnotation)
}
}
default:
shouldDraw = false
break
}
}
}
}
func isPointWithinDrawingArea(_ point: CGPoint, in page: PDFPage, of pdfView: PDFView) -> Bool {
let drawingArea = CGRect(x: 0, y: 0, width: pdfView.bounds.width, height: pdfView.bounds.height * 0.9)
return drawingArea.contains(point)
}
func clearDrawing() {
guard let pdfView = self.pdfView, let currentPage = pdfView.currentPage else { return }
let paths = allPathsDict[currentPage] ?? []
paths.forEach { path in
let annotation = PDFAnnotation(bounds: currentPage.bounds(for: pdfView.displayBox), forType: .ink, withProperties: nil)
annotation.color = UIColor.blue.withAlphaComponent(0.9)
annotation.add(path)
currentPage.addAnnotation(annotation)
}
allPathsDict[currentPage]?.removeAll()
}
func savePDFWithAnnotations() -> String? {
guard let pdfView = self.pdfView else {
return nil
}
let newPdfDocument = PDFDocument()
for i in 0..<(pdfView.document!.pageCount ?? 0) {
if let originalPage = pdfView.document?.page(at: i) {
let newPage = PDFPage(image: originalPage.thumbnail(of: CGSize(width: originalPage.bounds(for: pdfView.displayBox).width, height: originalPage.bounds(for: pdfView.displayBox).height), for: pdfView.displayBox))!
if let paths = allPathsDict[originalPage], paths.count > 0 {
let annotation = PDFAnnotation(bounds: originalPage.bounds(for: pdfView.displayBox), forType: .ink, withProperties: nil)
annotation.color = UIColor.blue.withAlphaComponent(0.9)
paths.forEach { annotation.add($0) }
newPage.addAnnotation(annotation)
}
newPdfDocument.insert(newPage, at: i)
}
}
// Save the new PDF document with annotations
// if let data = newPdfDocument.dataRepresentation() {
// let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
// let pdfURL = documentsDirectory.appendingPathComponent("annotatedPDF.pdf")
//
// do {
// try data.write(to: pdfURL)
// print("PDF with annotations saved at: \(pdfURL)")
// } catch {
// print("Error saving PDF with annotations: \(error.localizedDescription)")
// }
// }
// saving the pdf as base64 string
if let data = newPdfDocument.dataRepresentation() {
let base64String = data.base64EncodedString()
return base64String
}
return nil
}
func clearLastAnnotation() {
guard let pdfView = self.pdfView else { return }
if let currentPage = pdfView.currentPage,
var paths = allPathsDict[currentPage],
let lastPath = paths.popLast() {
allPathsDict[currentPage] = paths
currentPage.annotations.forEach { currentPage.removeAnnotation($0) }
let updatedAnnotation = PDFAnnotation(bounds: currentPage.bounds(for: pdfView.displayBox), forType: .ink, withProperties: nil)
updatedAnnotation.color = UIColor.blue.withAlphaComponent(0.9)
paths.forEach { updatedAnnotation.add($0) }
currentPage.addAnnotation(updatedAnnotation)
}
}
func removeAllAnnotations() {
guard let pdfView = self.pdfView else { return }
for index in 0..<(pdfView.document?.pageCount ?? 0) {
if let page = pdfView.document?.page(at: index) {
let existingAnnotations = page.annotations
existingAnnotations.forEach { page.removeAnnotation($0) }
allPathsDict[page]?.removeAll()
}
}
if let currentPage = pdfView.currentPage {
allPathsDict[currentPage]?.removeAll()
}
}
func removeAnnotationsOnCurrentPage() {
guard let pdfView = self.pdfView, let currentPage = pdfView.currentPage else { return }
currentPage.annotations.forEach { annotation in
currentPage.removeAnnotation(annotation)
}
allPathsDict[currentPage] = []
}
}
清晰的注释: 在您的clearDrawing()方法中,您将清除的注释添加回currentPage。相反,您应该从 currentPage 中删除注释并清除 allPathsDict 中的相应路径。修改您的clearDrawing()方法如下:
func clearDrawing() {
guard let pdfView = self.pdfView, let currentPage = pdfView.currentPage else { return }
currentPage.annotations.forEach { annotation in
currentPage.removeAnnotation(annotation)
}
allPathsDict[currentPage]?.removeAll()
}
确保正确初始化: 确保您正在初始化 allPathsDict 并在需要时正确清除它。在协调器的初始化中,您可以清除所有路径:
init(parent: PDFViewContainerMulti) {
self.parent = parent
self.pdfView = parent.pdfView
// Clear all paths when the Coordinator is initialized
self.allPathsDict.removeAll()
}