SwiftUI PDF library
Nutrient iOS SDK exposes specific APIs for native integration with SwiftUI. This eliminates the need for manual PDFViewController wrapping when developing SwiftUI applications, enabling direct utilization of the SDK.
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: PSPDFKit.Document
var body: some View { PDFView(document: document)}Configuration
PDFView has special view modifiers to make configuring it as direct as possible in SwiftUI. The most important properties from PDFConfiguration are available. Not every option from PDFConfiguration is available as a view modifier for the PDFView yet, but the more widely used ones are.
Using these view modifiers in action would look something like this:
PDFView(document: document) .scrollDirection(.vertical) .pageTransition(.scrollContinuous) .pageMode(.single) .spreadFitting(.fill)If you need a configuration option that isn’t mapped to a view modifier yet, you can fall back to a PDFConfigurationBuilder. Configure the SwiftUI PDFView in the initializer, like this:
PDFView(document: document) { builder in builder.searchResultZoomScale = 2}Controller setup
The SDK exposes most configuration options, delegates, and actions in a SwiftUI-friendly way, so you need the underlying PDFViewController only for a few 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 the SDK calls 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
Use the bindings on PDFView to transfer state back and forth between your logic and SwiftUI, and both sides stay up to date automatically.
The available bindings are:
pageIndexBinding— Binds the currentpageIndexof the underlyingPDFViewController. It always reflects the current value of the page index. Changing it will set the page index onPDFViewController.viewModeBinding— Binds the currentviewModeof the underlyingPDFViewController. It always reflects the current value of the view mode. Changing it will set the view mode onPDFViewController.selectedAnnotationsBinding— Binds the currentselectedAnnotationsof the visiblePDFPageViewfrom 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)}Your screen may already have a navigation bar set up with UIKit, and you may want Nutrient iOS SDK to take it over. In that case, make sure PDFView is in the view hierarchy of the UIHostingController that’s added to a UINavigationController, like this:
struct ContentView: View { let document: PSPDFKit.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. Nutrient iOS SDK exposes individual buttons and sets of buttons that you can use in a toolbar. DefaultToolbarButtons provides a set of default buttons that offer common functions for all view modes. The default buttons may change in future releases of Nutrient iOS SDK.
When you set up toolbar buttons, you must provide a scope with the @PDFView.Scope property wrapper. Then set the scope with the pdfViewScope(_:) modifier in the view hierarchy that covers both the toolbar modifier and PDFView. Nutrient iOS SDK uses this scope to share state and configuration between the buttons and PDFView. The following code shows both steps:
@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 such as 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 modifier sets where the document title appears. It can appear only in the navigation bar, or in the document label, which floats above the document content. By default, it adapts based on the available width. You can show the document title like this:
PDFView(document: document) .showDocumentTitle()Publishers
The SDK also exposes some publishers, so you can keep track of changes in a 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(opens in a new tab).
They include documentPublisher and 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, because they show various SwiftUI use cases. You might also want to check out the dedicated SwiftUIDocumentBrowser example, which shows how to integrate Nutrient iOS SDK into a document-based SwiftUI app.