pdfkit

安装量: 480
排名: #4783

安装

npx skills add https://github.com/dpearson2699/swift-ios-skills --skill pdfkit

PDFKit Display, navigate, search, annotate, and manipulate PDF documents with PDFView , PDFDocument , PDFPage , PDFAnnotation , and PDFSelection . Targets Swift 6.3 / iOS 26+. Contents Setup Displaying PDFs Loading Documents Page Navigation Text Search and Selection Annotations Thumbnails SwiftUI Integration Common Mistakes Review Checklist References Setup PDFKit requires no entitlements or Info.plist entries. import PDFKit Platform availability: iOS 11+, iPadOS 11+, Mac Catalyst 13.1+, macOS 10.4+, tvOS 11+, visionOS 1.0+. Displaying PDFs PDFView is a UIView subclass that renders PDF content, handles zoom, scroll, text selection, and page navigation out of the box. import PDFKit import UIKit class PDFViewController : UIViewController { let pdfView = PDFView ( ) override func viewDidLoad ( ) { super . viewDidLoad ( ) pdfView . frame = view . bounds pdfView . autoresizingMask = [ . flexibleWidth , . flexibleHeight ] view . addSubview ( pdfView ) pdfView . autoScales = true pdfView . displayMode = . singlePageContinuous pdfView . displayDirection = . vertical if let url = Bundle . main . url ( forResource : "sample" , withExtension : "pdf" ) { pdfView . document = PDFDocument ( url : url ) } } } Display Modes Mode Behavior .singlePage One page at a time .singlePageContinuous Pages stacked vertically, scrollable .twoUp Two pages side by side .twoUpContinuous Two-up with continuous scrolling Scaling and Appearance pdfView . autoScales = true pdfView . minScaleFactor = pdfView . scaleFactorForSizeToFit pdfView . maxScaleFactor = 4.0 pdfView . displaysPageBreaks = true pdfView . pageShadowsEnabled = true pdfView . interpolationQuality = . high Loading Documents PDFDocument loads from a URL, Data , or can be created empty. let fileDoc = PDFDocument ( url : fileURL ) let dataDoc = PDFDocument ( data : pdfData ) let emptyDoc = PDFDocument ( ) Password-Protected PDFs guard let document = PDFDocument ( url : url ) else { return } if document . isLocked { if ! document . unlock ( withPassword : userPassword ) { // Show password prompt } } Saving and Page Manipulation document . write ( to : outputURL ) document . write ( to : outputURL , withOptions : [ . ownerPasswordOption : "ownerPass" , . userPasswordOption : "userPass" ] ) let data = document . dataRepresentation ( ) // Pages (0-based) let count = document . pageCount document . insert ( PDFPage ( ) , at : count ) document . removePage ( at : 2 ) document . exchangePage ( at : 0 , withPageAt : 3 ) Page Navigation PDFView provides built-in navigation with history tracking. // Go to a specific page if let page = pdfView . document ? . page ( at : 5 ) { pdfView . go ( to : page ) } // Sequential navigation pdfView . goToNextPage ( nil ) pdfView . goToPreviousPage ( nil ) pdfView . goToFirstPage ( nil ) pdfView . goToLastPage ( nil ) // Check navigation state if pdfView . canGoToNextPage { / ... / } // History navigation if pdfView . canGoBack { pdfView . goBack ( nil ) } // Go to a specific point on a page let destination = PDFDestination ( page : page , at : CGPoint ( x : 0 , y : 500 ) ) pdfView . go ( to : destination ) Observing Page Changes NotificationCenter . default . addObserver ( self , selector :

selector

( pageChanged ) , name : . PDFViewPageChanged , object : pdfView ) @objc func pageChanged ( _ notification : Notification ) { guard let page = pdfView . currentPage , let doc = pdfView . document else { return } let index = doc . index ( for : page ) pageLabel . text = "Page ( index + 1 ) of ( doc . pageCount ) " } Text Search and Selection Synchronous Search let results : [ PDFSelection ] = document . findString ( "search term" , withOptions : [ . caseInsensitive ] ) Asynchronous Search Use PDFDocumentDelegate for background searches on large documents. Implement didMatchString(:) to receive each match and documentDidEndDocumentFind(:) for completion. Incremental Search and Find Interaction // Find next match from current selection let next = document . findString ( "term" , fromSelection : current , withOptions : [ . caseInsensitive ] ) // System find bar (iOS 16+) pdfView . isFindInteractionEnabled = true Text Extraction let fullText = document . string // Entire document let pageText = document . page ( at : 0 ) ? . string // Single page let attributed = document . page ( at : 0 ) ? . attributedString // With formatting // Region-based extraction if let page = document . page ( at : 0 ) { let selection = page . selection ( for : CGRect ( x : 50 , y : 50 , width : 400 , height : 200 ) ) let text = selection ? . string } Highlighting Search Results let results = document . findString ( "important" , withOptions : [ . caseInsensitive ] ) for selection in results { selection . color = . yellow } pdfView . highlightedSelections = results if let first = results . first { pdfView . setCurrentSelection ( first , animate : true ) pdfView . go ( to : first ) } Annotations Annotations are created with PDFAnnotation(bounds:forType:withProperties:) and added to a PDFPage . Highlight Annotation func addHighlight ( to page : PDFPage , selection : PDFSelection ) { let highlight = PDFAnnotation ( bounds : selection . bounds ( for : page ) , forType : . highlight , withProperties : nil ) highlight . color = UIColor . yellow . withAlphaComponent ( 0.5 ) page . addAnnotation ( highlight ) } Text Note Annotation let note = PDFAnnotation ( bounds : CGRect ( x : 100 , y : 700 , width : 30 , height : 30 ) , forType : . text , withProperties : nil ) note . contents = "This is a sticky note." note . color = . systemYellow note . iconType = . comment page . addAnnotation ( note ) Free Text Annotation let freeText = PDFAnnotation ( bounds : CGRect ( x : 50 , y : 600 , width : 300 , height : 40 ) , forType : . freeText , withProperties : nil ) freeText . contents = "Added commentary" freeText . font = UIFont . systemFont ( ofSize : 14 ) freeText . fontColor = . darkGray page . addAnnotation ( freeText ) Link Annotation let link = PDFAnnotation ( bounds : CGRect ( x : 50 , y : 500 , width : 200 , height : 20 ) , forType : . link , withProperties : nil ) link . url = URL ( string : "https://example.com" ) page . addAnnotation ( link ) // Internal page link link . destination = PDFDestination ( page : targetPage , at : . zero ) Removing Annotations for annotation in page . annotations { page . removeAnnotation ( annotation ) } Annotation Subtypes Reference Subtype Constant Purpose Highlight .highlight Text markup (yellow highlight) Underline .underline Text markup (underline) StrikeOut .strikeOut Text markup (strikethrough) Text .text Sticky note icon FreeText .freeText Inline text block Ink .ink Freehand drawing paths Link .link URL or page destination Line .line Straight line with endpoints Square .square Rectangle shape Circle .circle Ellipse shape Stamp .stamp Rubber stamp (Approved, etc.) Widget .widget Form element (text field, checkbox) Thumbnails PDFThumbnailView PDFThumbnailView shows a strip of page thumbnails linked to a PDFView . let thumbnailView = PDFThumbnailView ( ) thumbnailView . pdfView = pdfView thumbnailView . thumbnailSize = CGSize ( width : 60 , height : 80 ) thumbnailView . layoutMode = . vertical thumbnailView . translatesAutoresizingMaskIntoConstraints = false view . addSubview ( thumbnailView ) Generating Thumbnails Programmatically let thumbnail = page . thumbnail ( of : CGSize ( width : 120 , height : 160 ) , for : . mediaBox ) // All pages let thumbnails = ( 0 ..< document . pageCount ) . compactMap { document . page ( at : $0 ) ? . thumbnail ( of : CGSize ( width : 120 , height : 160 ) , for : . mediaBox ) } SwiftUI Integration Wrap PDFView in a UIViewRepresentable for SwiftUI. import SwiftUI import PDFKit struct PDFKitView : UIViewRepresentable { let document : PDFDocument func makeUIView ( context : Context ) -> PDFView { let pdfView = PDFView ( ) pdfView . autoScales = true pdfView . displayMode = . singlePageContinuous pdfView . document = document return pdfView } func updateUIView ( _ pdfView : PDFView , context : Context ) { if pdfView . document !== document { pdfView . document = document } } } Usage struct DocumentScreen : View { let url : URL var body : some View { if let document = PDFDocument ( url : url ) { PDFKitView ( document : document ) . ignoresSafeArea ( ) } else { ContentUnavailableView ( "Unable to load PDF" , systemImage : "doc.questionmark" ) } } } For interactive wrappers with page tracking, annotation hit detection, and coordinator patterns, see references/pdfkit-patterns.md . Page Overlays (iOS 16+) PDFPageOverlayViewProvider places UIKit views on top of individual pages for interactive controls or custom rendering beyond standard annotations. class OverlayProvider : NSObject , PDFPageOverlayViewProvider { func pdfView ( _ view : PDFView , overlayViewFor page : PDFPage ) -> UIView ? { let overlay = UIView ( ) // Add custom subviews return overlay } } pdfView . pageOverlayViewProvider = overlayProvider Common Mistakes DON'T: Force-unwrap PDFDocument init PDFDocument(url:) and PDFDocument(data:) are failable initializers. // WRONG let document = PDFDocument ( url : url ) ! // CORRECT guard let document = PDFDocument ( url : url ) else { return } DON'T: Forget autoScales on PDFView Without autoScales , the PDF renders at its native resolution. // WRONG pdfView . document = document // CORRECT pdfView . autoScales = true pdfView . document = document DON'T: Ignore PDF coordinate system in annotations PDF page coordinates have origin at the bottom-left with Y increasing upward -- opposite of UIKit. // WRONG: UIKit coordinates let bounds = CGRect ( x : 50 , y : 50 , width : 200 , height : 30 ) // CORRECT: PDF coordinates (origin bottom-left) let pageBounds = page . bounds ( for : . mediaBox ) let pdfY = pageBounds . height - 50 - 30 let bounds = CGRect ( x : 50 , y : pdfY , width : 200 , height : 30 ) DON'T: Modify annotations on a background thread PDFKit classes are not thread-safe. // WRONG DispatchQueue . global ( ) . async { page . addAnnotation ( annotation ) } // CORRECT DispatchQueue . main . async { page . addAnnotation ( annotation ) } DON'T: Compare PDFDocument with == in UIViewRepresentable PDFDocument is a reference type. Use identity ( !== ). // WRONG: Always replaces document func updateUIView ( _ pdfView : PDFView , context : Context ) { pdfView . document = document } // CORRECT func updateUIView ( _ pdfView : PDFView , context : Context ) { if pdfView . document !== document { pdfView . document = document } } Review Checklist PDFDocument init uses optional binding, not force-unwrap pdfView.autoScales = true set for proper initial display Page indices checked against pageCount before access displayMode and displayDirection configured to match design Annotations use PDF coordinate space (origin bottom-left, Y up) All PDFKit mutations happen on the main thread Password-protected PDFs handled with isLocked / unlock(withPassword:) SwiftUI wrapper uses !== identity check in updateUIView PDFViewPageChanged notification observed for page tracking PDFThumbnailView.pdfView linked to the main PDFView Large-document search uses async beginFindString with delegate Saved documents use write(to:withOptions:) when encryption needed References Extended patterns (forms, watermarks, merging, printing, overlays, outlines, custom drawing): references/pdfkit-patterns.md PDFKit framework PDFView PDFDocument PDFPage PDFAnnotation PDFSelection PDFThumbnailView PDFPageOverlayViewProvider Adding Widgets to a PDF Document Adding Custom Graphics to a PDF

返回排行榜