SwiftUI PDF Library
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
in the initializer, like this:
PDFView(document: document) { builder in builder.searchResultZoomScale = 2 }
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 want to access properties or methods of PDFViewController
that aren’t yet available in SwiftUI, use the following 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)") }
You can find the exposed delegate view modifiers in the API documentation.
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) .toolbar { 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
To make PDFView
show a navigation bar, you can wrap it in a NavigationView
or NavigationStack
, like this:
NavigationStack { PDFView(document: document) }
If you’re integrating PDFView
in a screen in your app that already has a navigation bar set up using UIKit and you want PSPDFKit to take it over, make sure PDFView
is in the view hierarchy of the UIHostingController
that’s added in a UINavigationController
, like this:
struct ContentView: View { let document: Document var body: some View { PDFView(document: document) } } let hostingController = UIHostingController(rootView: ContentView(document: document)) navigationController.pushViewController(hostingController, animated: true)
By default, PDFView
won’t add any buttons or set the title of the navigation bar. To learn how to add buttons or set the title, refer to the following sections.
Toolbar Buttons
To add toolbar buttons to your PDFView
, you can use the SwiftUI toolbar(_:)
modifier. PSPDFKit exposes a variety of buttons or a set of buttons that can be used in a toolbar. DefaultToolbarButtons
provides a set of default buttons that offer common functionalities for all different view modes. The default buttons may change in future releases of PSPDFKit.
When setting up toolbar buttons, you must provide a scope using the @PDFView.Scope
property wrapper and set it using the pdfViewScope(_:)
modifier in the view hierarchy that covers both the toolbar modifier and PDFView
. PSPDFKit uses this scope to share state and configuration between the buttons and PDFView
. This can be done like this:
@PDFView.Scope var scope PDFView(document: document) .toolbar { DefaultToolbarButtons() } .pdfViewScope(scope)
You can also individually show buttons to fit your application’s specific needs by using views like AnnotationButton
, ThumbnailsButton
, or ContentEditingButton
, like this:
@PDFView.Scope var scope PDFView(document: document) .toolbar { ContentEditingButton() } .pdfViewScope(scope)
Navigation Bar Title
To control whether the document title is shown in the navigation bar, use the showDocumentTitle(_:)
modifier. This sets whether the document title should only be shown in the navigation bar, shown in the document label (which floats above document content), or adapt based on the available width, which is the default. You can show the document title like this:
PDFView(document: document)
.showDocumentTitle()
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.