Customizing PDF Viewer Styling on iOS
To seamlessly integrate PSPDFKit into your application, you will likely want to adjust some of the appearance settings of the framework UI elements. PSPDFKit was designed to be very flexible in this regard and offers a wide variety of appearance-centric properties and customization hooks.
Tint Color
PSPDFKit conforms to the standard UIView
tintColor
inheritance scheme and will automatically adopt your application’s global tint color. You can set the desired PSPDFKit tintColor
by setting the tintColor
property on your current window or on any other common superview of PSPDFKit view components. You are also free to set the tintColor
property on any of the PSPDFKit UIView
subclasses, either by setting the instance property directly or by using the UIAppearance
protocol.
Status Bar
PSPDFKit was designed with a view controller-based status bar appearance in mind. In order to get the correct status bar appearance and behaviors for PSPDFKit view controllers, ensure the UIViewControllerBasedStatusBarAppearance
flag in your app’s Info.plist
is set. (This is the default behavior, but some old products might have set this to NO
. In that case, you first need to update your application.)
ℹ️ Note: When the application root view controller is a
UINavigationController
instance, the status bar appearance is deferred by thebarStyle
property of the navigation controller’snavigationBar
. Therefore, if you showPDFViewController
in aUINavigationController
, be sure to correctly set the navigation barbarStyle
in order to get the desired status bar style.
UIAppearance
The recommended and easiest way to style PSPDFKit to your liking is using the UIAppearance
protocol. PSPDFKit instance properties that were designed to be used with UIAppearance
are marked with the standard UI_APPEARANCE_SELECTOR
qualifier.
ℹ️ Note: It is important that you apply
UIAppearance
settings early in your application (or view controller) lifecycle. The appearance settings should be in place beforeviewDidLoad()
is called.
UINavigationBar and UIToolbar Styling
Two of the most likely candidates for appearance customization are UINavigationBar
and UIToolbar
. If you are already setting the appearance of either one using UIAppearance
selectors in your app, PSPDFKit will inherit these settings.
However, applying default styles to UINavigationBar
and UIToolbar
directly will have no effect on instances created by the PSPDFKit framework and might have the unwanted side effect of also leaking certain appearance styles to system-provided view controllers (like MFMailComposeViewController
). Thus we recommended that you instead limit the UINavigationBar
and UIToolbar
customization to your application only. In order to achieve this with PSPDFKit as well, you can limit the appearance customization to instances inside PDFNavigationController
. PDFNavigationController
is a simple UINavigationController
subclass that adds some additional features and is used throughout PSPDFKit. If you’re presenting PDFViewController
inside a UINavigationController
(the most common case), you might want to use PDFNavigationController
to ease styling. If you’re using your own UINavigationController
or embedding PDFViewController
in another view controller, it will be your responsibility to style the container controller and use the correct appearance bounding for UINavigationBar
and UIToolbar
.
ℹ️ Note: Customizing the bar appearance (including the background color) needs to be done using the
UIBarAppearance
API instead of the legacy customization API. This applies to navigation bars, the scrubber bar (both floating and docked), and all the toolbars. You can set the bar appearance using thestandardAppearance
andcompactAppearance
properties onUINavigationBar
,ScrubberBar
, andToolbar
(the superclass ofAnnotationToolbar
,PDFDocumentEditorToolbar
, andFreeTextAccessoryView
, respectively).
Basic Appearance Customization Example
let mainColor: UIColor = UIColor(white: 0.2, alpha: 1) let secondaryColor = UIColor.systemOrange // Update the window's `tintColor` as soon as a new window is created. currentWindow.tintColor = mainColor; // Navigation bar and toolbar customization. We're limiting appearance customization to instances that are // inside `PDFNavigationController` so that we don't affect the appearance of certain system controllers. let navBarProxy = UINavigationBar.appearance(whenContainedInInstancesOf: [PDFNavigationController.self]) let toolbarProxy = UIToolbar.appearance(whenContainedInInstancesOf: [PDFNavigationController.self]) // `UINavigationBar` styling. let navigationBarAppearance = UINavigationBarAppearance() navigationBarAppearance.backgroundColor = mainColor navBarProxy.standardAppearance = navigationBarAppearance navBarProxy.compactAppearance = navigationBarAppearance navBarProxy.scrollEdgeAppearance = navigationBarAppearance // `UIToolbar` styling. let toolbarAppearance = UIToolbarAppearance() toolbarAppearance.backgroundColor = mainColor toolbarProxy.standardAppearance = toolbarAppearance toolbarProxy.compactAppearance = toolbarAppearance // Make sure we're getting a light title and status bar. navBarProxy.overrideUserInterfaceStyle = .dark navBarProxy.tintColor = secondaryColor toolbarProxy.tintColor = secondaryColor
UIColor *mainColor = [UIColor colorWithWhite:0.2f alpha:1.f]; UIColor *secondaryColor = [UIColor systemOrangeColor]; // Update the window's `tintColor` as soon as a new window is created. currentWindow.tintColor = mainColor; // Navigation bar and toolbar customization. We're limiting appearance customization to instances that are // inside `PSPDFNavigationController` so that we don't affect the appearance of certain system controllers. UINavigationBar *navBarProxy = [UINavigationBar appearanceWhenContainedInInstancesOfClasses:@[PSPDFNavigationController.class]]; UIToolbar *toolbarProxy = [UIToolbar appearanceWhenContainedInInstancesOfClasses:@[PSPDFNavigationController.class]]; // `UINavigationBar` styling. UINavigationBarAppearance *navigationBarAppearance = [[UINavigationBarAppearance alloc] init]; navigationBarAppearance.backgroundColor = mainColor; navBarProxy.standardAppearance = navigationBarAppearance; navBarProxy.compactAppearance = navigationBarAppearance; navBarProxy.scrollEdgeAppearance = navigationBarAppearance; // `UIToolbar` styling. UIToolbarAppearance *toolbarAppearance = [[UIToolbarAppearance alloc] init]; toolbarAppearance.backgroundColor = mainColor; // Apply the same appearance styling to all sizes of `UIToolbar`. toolbarProxy.standardAppearance = toolbarAppearance; toolbarProxy.compactAppearance = toolbarAppearance; // Make sure we're getting a light title and status bar. navBarProxy.overrideUserInterfaceStyle = UIUserInterfaceStyleDark; navBarProxy.tintColor = secondaryColor; toolbarProxy.tintColor = secondaryColor;
For a live example, please take a look at PSCAppDelegate.customizeAppearanceOfNavigationBar()
and PSCAppDelegate.customizeAppearanceOfToolbar()
in the PSPDFKit Catalog.
UINavigationBar and UIToolbar in Popovers
By default, the UINavigationBar
and UIToolbar
instances contained in a PDFNavigationController
presented as a popover are reset to their default iOS appearances by PSPDFKit. This ensures that the bars seamlessly blend with the default popover background view.
If you want to override this behavior, you can do so in your initialization code. The styling code should be similar to the Basic Appearance Customization Example above, with the exception that we add PDFNavigationController
and UIPopoverPresentationController
to the hierarchy of container classes. This is so that the appearance proxy will only apply styling when we have a navigation bar embedded within a PDFNavigationController
embedded within a UIPopoverPresentationController
. Here’s how it would look:
let navBarPopoverProxy = UINavigationBar.appearance(whenContainedInInstancesOf: [PDFNavigationController.self, UIPopoverPresentationController.self]) let toolbarPopoverProxy = UIToolbar.appearance(whenContainedInInstancesOf: [PDFNavigationController.self, UIPopoverPresentationController.self])
UINavigationBar *navBarPopoverProxy = [UINavigationBar appearanceWhenContainedInInstancesOfClasses:@[PSPDFNavigationController.class, UIPopoverPresentationController.class]]; UIToolbar *toolbarPopoverProxy = [UIToolbar appearanceWhenContainedInInstancesOfClasses:@[PSPDFNavigationController.class, UIPopoverPresentationController.class]];
The style of the buttons (normal and selected) added to UINavigationBar
and UIToolbar
is inherited from the bars themselves. The tint color for these buttons is updated to match the tint color of the bars they’ve been added to, while the background color is nil
. For the selected style of the buttons, the tint color is changed to that of the background color of the bar they’ve been added to, and a background color is set, which is the tint color of the bar.
Normal State | Selected State |
---|---|
Customizing Bars Using UIAppearance with SwiftUI
Because SwiftUI offers more limited customization options than UIKit, some apps primarily using SwiftUI choose to customize the appearance of navigation bars, toolbars, and tab bars using UIAppearance
. For example, as of iOS 18, UIAppearance
is the only way to use a custom font for the navigation bar title.
To avoid transparent bar backgrounds in a default SwiftUI setup, PDFView
uses these modifiers internally:
.toolbarBackground(.visible, for: .navigationBar) .toolbarBackground(.visible, for: .tabBar)
A side effect of this is resetting all appearance properties of the bars, overriding customizations set up with UIAppearance
while the PDFView
is visible. To avoid this, add these modifiers to your PDFView
:
PDFView(...)
.toolbarBackground(.automatic, for: .navigationBar)
.toolbarBackground(.automatic, for: .tabBar)
This results in SwiftUI leaving the bars alone, so UIAppearance
customizations remain in place.
Annotation Toolbar
AnnotationToolbar
(and its superclass, FlexibleToolbar
) will attempt to automatically set its appearance parameters to match those of the UINavigationBar
of the UINavigationController
in which it is currently being displayed. In case these parameters aren’t appropriate, or if further customization is required, you can use the appearance properties defined in FlexibleToolbar
to adjust the toolbar styling (using the UIAppearance
protocol or setting the property values directly).
The following is an example illustrating how to customize just the annotation toolbar appearance (changing it from the default inferred appearance). You can customize the scrubber bar exactly the same way by changing AnnotationToolbar
to ScrubberBar
on the first line:
let annotationToolbarProxy = AnnotationToolbar.appearance() let barColor = UIColor.systemOrange let appearance = UIToolbarAppearance() appearance.backgroundColor = barColor annotationToolbarProxy.standardAppearance = appearance annotationToolbarProxy.compactAppearance = appearance annotationToolbarProxy.tintColor = UIColor(white: 0.2, alpha: 1)
PSPDFAnnotationToolbar *annotationToolbarProxy = [PSPDFAnnotationToolbar appearance]; UIColor *barColor = UIColor.systemOrangeColor; UIToolbarAppearance *appearance = [[UIToolbarAppearance alloc] init]; appearance.backgroundColor = barColor; annotationToolbarProxy.standardAppearance = appearance; annotationToolbarProxy.compactAppearance = appearance; annotationToolbarProxy.tintColor = [UIColor colorWithWhite:0.2f alpha:1.f];
The buttons added to the annotation toolbar follow a styling similar to that of the buttons added to the navigation and toolbar created by PSPDFKit: No background color is set for the normal state of the buttons, and the tint color is same as that of the annotation toolbar. Meanwhile, for the selected button state, the annotation toolbar tint color is set as the background color of the button, and the background color is set as the tint color of the button.
Normal State | Selected State |
---|---|
However, the selected style for the buttons added to an annotation bar can be further customizied by adding the following:
annotationToolbarProxy.selectedBackgroundColor = UIColor(white: 0.8, alpha: 1) annotationToolbarProxy.selectedTintColor = UIColor(white: 0.2, alpha: 1)
[annotationToolbarProxy setSelectedBackgroundColor:[UIColor colorWithWhite:0.8f alpha:1.f]]; [annotationToolbarProxy setSelectedTintColor:[UIColor colorWithWhite:0.2f alpha:1.f]];
Changing the Scrubber Bar Background Color without UIAppearance
An alternative to using the UIAppearance
proxy is to set the properties on the object directly:
let scrubberBar = pdfViewController.userInterfaceView.scrubberBar let barColor = .systemOrange let appearance = UIToolbarAppearance() appearance.backgroundColor = barColor scrubberBar.standardAppearance = appearance scrubberBar.compactAppearance = appearance
PSPDFScrubberBar *scrubberBar = pdfViewController.userInterfaceView.scrubberBar; UIColor *barColor = UIColor.systemOrangeColor; UIToolbarAppearance *appearance = [[UIToolbarAppearance alloc] init]; appearance.backgroundColor = barColor; scrubberBar.standardAppearance = appearance; scrubberBar.compactAppearance = appearance
Font Customization
You can change the font of a view when it’s contained in a specific view controller class. For example, you can change the font of a UITextView
when it’s contained in a NoteAnnotationViewController
:
let textView = UITextView.appearance(whenContainedInInstancesOf: [PSPDFNoteAnnotationViewController.self]) textView.font = UIFont(name: "Courier", size: 14)
UITextView *textView = [UITextView appearanceWhenContainedInInstancesOfClasses:@[[PSPDFNoteAnnotationViewController class]]]; textView.font = [UIFont fontWithName:@"Courier" size:14.f];