SwiftUI PDF Library
Since version 10.1 for iOS, PSPDFKit exposes specific APIs to use PSPDFKit with SwiftUI out of the box. This makes dealing with PSPDFKit in a SwiftUI app easier, and it doesn’t require you to wrap PDFViewController
yourself if you want to go the SwiftUI route.
The main entry point is the PDFView
struct
, which conforms to SwiftUI’s View
protocol. PDFView
wraps PDFViewController
into a SwiftUI-compatible container.
Showing a PDF
To show a PDF, use PDFView
in the body
of your SwiftUI view, and pass it a Document
:
var document: Document var body: some View { PDFView(document: document) }
Configuration
PDFView
has special view modifiers to make configuring it as easy as possible in SwiftUI. The most important properties from PDFConfiguration
are available. While currently not all available options from PDFConfiguration
are available as view modifiers for the PDFView
, the more widely used configuration options are available.
Using these view modifiers in action would look something like this:
PDFView(document: document)
.scrollDirection(.vertical)
.pageTransition(.scrollContinuous)
.pageMode(.single)
.spreadFitting(.fill)
In case you ever find yourself needing a configuration option that hasn’t yet been mapped to a view modifier, you can always fall back to using a PDFConfigurationBuilder
and configuring the SwiftUI PDFView
with the conventional options by using the updateConfiguration(builder:)
view modifier, like this:
PDFView(document: document) .updateConfiguration { builder in builder.searchResultZoomScale = 2 }
These are all the view modifier configurations available:
Controller Setup
Since most configuration options, delegates, and actions are exposed in a SwiftUI-friendly way, there are only a few reasons why you should fall back to using the underlying PDFViewController
for more advanced setups. You can access the PDFViewController
via the updateControllerConfiguration(block:)
view modifier.
For example, if you use a parent navigation bar but not a custom navigation bar, you’d want to use the following navigation bar configuration:
PDFView(document: document) .updateControllerConfiguration { pdfController in // Use the underlying PDFViewController (pdfController) here. }
Delegates
Some of the most relevant delegate methods from PDFViewControllerDelegate
are exposed using view modifiers that take a closure, which are called when a corresponding event happens.
To get a callback whenever a page is displayed, you can use this:
PDFView(document: document) .onWillBeginDisplayingPageView { _, pageIndex in print("Displaying page \(pageIndex)") }
All the exposed delegate view modifiers are listed below:
Actions
Executing actions on the PDFView
can also be done in SwiftUI. For this, we expose the actionEventPublisher
subject. You can send various events to this subject to execute all kinds of actions. The action events are of type ActionEvent
:
@State var actionEventPublisher = PassthroughSubject<PDFView.ActionEvent, Never>() PDFView(document: document, actionEventPublisher: actionEventPublisher) .navigationBarItems(trailing: HStack { Button("Next Page") { actionEventPublisher.send(.scrollToNextSpread(animated: true)) } } )
Bindings
The bindings on PDFView
can be used to transfer state back and forth between your logic and SwiftUI, with both sides always being automatically up to date.
The available bindings are:
-
pageIndexBinding
— Binds the currentpageIndex
of the underlyingPDFViewController
. It always reflects the current value of the page index. Changing it will set the page index onPDFViewController
. -
viewModeBinding
— Binds the currentviewMode
of the underlyingPDFViewController
. It always reflects the current value of the view mode. Changing it will set the view mode onPDFViewController
. -
selectedAnnotationsBinding
— Binds the currentselectedAnnotations
of the visiblePDFPageView
from the underlyingPDFViewController
. It always reflects the current value of the selected annotations. Changing it will set the selected annotations on the visible page view. Note that all the annotations that will be set in this binding need to be on the same page.
All of these are provided in the initializer using the Binding
property wrapper.
For example, to add a stepper that changes the current page next to a label indicating the current page index, you can use this code snippet:
@State var pageIndex = PageIndex(0) VStack { Stepper("Current Page: \(pageIndex + 1)", value: $pageIndex, in: 0...document.pageCount - 1) PDFView(document: document, pageIndex: $pageIndex) }
Navigation Bar Setup
If you’re integrating PDFView
in a screen in your app that already has a navigation bar and you want PSPDFKit to take it over, you can add the useParentNavigationBar(true)
view modifier. It could look like this:
PDFView(document: document) .useParentNavigationBar(true) .updateControllerConfiguration { controller in controller.navigationItem.setRightBarButtonItems( [controller.thumbnailsButtonItem, controller.annotationButtonItem], for: .document, animated: false)
To make PDFView
use a custom navigation bar, you can wrap it in a NavigationView
:
NavigationView { PDFView(document: document) }
Publishers
Additionally, there are some publishers exposed, allowing you to keep track of changes in an easier, more SwiftUI-friendly way.
While this API is comfortable to use in SwiftUI, it’s not exclusive to SwiftUI; it can also be used when integrating PDFViewController
traditionally via UIKit.
These publishers are built on top of Apple’s Combine framework.
They include documentPublisher
, pageIndexPublisher
on PDFViewController
and savePublisher
, and annotationChangePublisher
on Document
.
Examples
For more details on how to integrate PDFView
, look at the SwiftUI examples in the Catalog example project, as they show various use cases when using SwiftUI. You might also want to check out the dedicated SwiftUIDocumentBrowser
example, which shows how to integrate PSPDFKit into a document-based SwiftUI app.