Customizing the Annotation Toolbar on iOS
The AnnotationToolbar
in PSPDFKit was designed to be flexible and highly configurable. It’s based on the FlexibleToolbar
, which is a subclass of UIView
and not UIToolbar
. Early versions of PSPDFKit used a toolbar-based version, but it turned out to be too inflexible.
By default, the annotation toolbar can either dock to the top or anchor on the left/right side of the PDFViewController
’s view.
This is fully configurable via setting FlexibleToolbar.Position
and setting either supportedToolbarPositions
or toolbarPosition
on the toolbar:
-
.inTopBar
-
.left
-
.right
-
.top
-
.horizontal
-
.vertical
-
.default
-
.all
If
FlexibleToolbar.Position.top
is a supported toolbar position, you must disable the document label by settingdocumentLabelEnabled
toAdaptiveConditional.NO
in yourPDFConfiguration
. Otherwise, an assertion will occur.
Presentation
The annotation toolbar can be shown or hidden using the annotationButtonItem
defined on PDFViewController
. This bar button item is already part of the default rightBarButtonItems
on NavigationItem
. If you like, you can of course customize its placement to your liking.
If you want to invoke the annotation toolbar programmatically, you have two options.
You can invoke the annotationButtonItem
by using action dispatching:
let annotationButtonItem = pdfController.annotationButtonItem let action = annotationButtonItem.action! UIApplication.shared.sendAction(action, to: annotationButtonItem.target, from: nil, for: nil)
UIBarButtonItem *annotationButtonItem = pdfController.annotationButtonItem; [UIApplication.sharedApplication sendAction:annotationButtonItem.action to:annotationButtonItem.target from:nil forEvent:nil];
Or you can toggle the toolbar manually:
// If not in document view mode, it'll be weird. pdfController.setViewMode(.document, animated: true) pdfController.annotationToolbarController?.updateHostView(nil, container: nil, viewController: pdfController) UsernameHelper.ask(forDefaultAnnotationUsernameIfNeeded: pdfController, completionBlock: { _ in pdfController.annotationToolbarController?.toggleToolbar(animated: true) })
// If not in document view mode, it'll be weird.
[pdfController setViewMode:PSPDFViewModeDocument animated:YES];
[pdfController.annotationToolbarController updateHostView:nil container:nil viewController:pdfController];
[PSPDFUsernameHelper askForDefaultAnnotationUsernameIfNeeded:pdfController completionBlock:^(NSString *userName) {
[pdfController.annotationToolbarController toggleToolbarAnimated:YES];
}];
Asking for the user’s author name is an optional (but recommended) step. This way, you’ll ensure the newly created annotations are associated with the correct author name.
Toolbar Buttons
Annotation Buttons
The annotation toolbar utilizes button grouping order to efficiently display a large amount of annotation tools. The toolbar comes preconfigured with default annotation groups for both iPad and iPhone, but you can also set your own groups by assigning new groups, which is done by creating an AnnotationToolConfiguration
object.
Toolbar groups are defined as an array of AnnotationToolConfiguration.ToolGroup
objects, which themselves contain AnnotationToolConfiguration.ToolItem
instances:
let configuration = AnnotationToolConfiguration(annotationGroups: [ AnnotationToolConfiguration.ToolGroup(items: [ AnnotationToolConfiguration.ToolItem(type: .ink, variant: .inkPen, configurationBlock: AnnotationToolConfiguration.ToolItem.inkConfigurationBlock()) ]), AnnotationToolConfiguration.ToolGroup(items: [ AnnotationToolConfiguration.ToolItem(type: .line), AnnotationToolConfiguration.ToolItem(type: .polyLine) ]) ])
PSPDFAnnotationToolbarConfiguration *configuration = [[PSPDFAnnotationToolbarConfiguration alloc] initWithAnnotationGroups:@[ [PSPDFAnnotationGroup groupWithItems:@[ [PSPDFAnnotationGroupItem itemWithType:PSPDFAnnotationStringInk variant:PSPDFAnnotationVariantStringInkPen configurationBlock:[PSPDFAnnotationGroupItem inkConfigurationBlock]] ]], [PSPDFAnnotationGroup groupWithItems:@[ [PSPDFAnnotationGroupItem itemWithType:PSPDFAnnotationStringLine], [PSPDFAnnotationGroupItem itemWithType:PSPDFAnnotationStringPolyLine] ]] ]];
Finally, to set the AnnotationToolConfiguration
in your PDFViewController
, you can use this code after creating the PDFViewController
:
controller.annotationToolbarController?.annotationToolbar.configurations = [configuration]
controller.annotationToolbarController.annotationToolbar.configurations = @[configuration];
To get the default button icons for tools with variants, pass one of the following as the configurationBlock
argument of the ToolItem
initializer:
-
AnnotationToolConfiguration.ToolItem.inkConfigurationBlock()
-
AnnotationToolConfiguration.ToolItem.lineConfigurationBlock()
-
AnnotationToolConfiguration.ToolItem.freeTextConfigurationBlock()
-
AnnotationToolConfiguration.ToolItem.polygonConfigurationBlock()
-
AnnotationToolConfiguration.ToolItem.measurementConfigurationBlock()
To customize the button icon, return a UIImage
containing your custom icon from the configurationBlock
. Whenever possible, try to return a template image from the configuration block (UIImageRenderingModeAlwaysTemplate
):
let configurationBlock = { (item: AnnotationToolConfiguration.ToolItem, container: AnyObject?, tintColor: UIColor) -> UIImage in let image = UIImage(named: "Custom Button Icon")! return image.withRenderingMode(.alwaysTemplate) }
PSPDFAnnotationGroupItemConfigurationBlock configurationBlock = ^UIImage *(PSPDFAnnotationGroupItem *item, id container, UIColor *tintColor) { UIImage *image = [UIImage imageNamed:@"Custom Button Icon"]; return [image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; };
Use the provided tint color only when you need multi-color images.
You can disable annotation toolbar configurations by setting the configuration property to nil
. In such a case, the toolbar will show a list of all editableAnnotationTypes
without any grouping.
Standard Buttons
In addition to the annotation group buttons, the toolbar also provides some additional buttons to manage toolbar presentation, undo/redo actions, and access the style manager. The buttons are automatically added or omitted, depending on the toolbar and PSPDFKit configuration settings. These buttons can be customized by overriding the doneButton
, undoButton
, redoButton
, and strokeColorButton
properties. The buttons can also be completely removed by returning nil
from the overridden getters.
To override the properties, you’ll have to subclass AnnotationToolbar
. Please read the overriding classes guide for more information.
Custom Buttons
The annotation toolbar also provides a convenient hook to add additional non-annotation type-specific buttons to the toolbar. You add these buttons by assigning an array of ToolbarButton
items to the additionalButtons
property on the annotation toolbar. The buttons will be positioned in between the annotation buttons and the undo/redo buttons.
Button Overflow
The toolbar usually auto-sizes to accommodate all of its buttons. If this cannot be achieved due lack of available view real estate, the toolbar automatically clips buttons flagged with the collapsible
flag (from ToolbarButton
) and groups them in a special collapsedButtons
item.
Auto Sizing
In vertical mode, the annotation toolbar will automatically size its height depending on the available screen real estate, the available toolbar configurations, and the active standard toolbar buttons. The final toolbar height is determined by first querying FlexibleToolbarContainerDelegate.flexibleToolbarContainerContentRect(_:for:)
, a method PDFViewController
implements and one you could override if you have custom elements that the toolbar should avoid. The toolbar then checks the required sizing constraints of all registered toolbar configurations and related standard buttons, trying to find the configuration that best fits the rect that flexibleToolbarContainerContentRect(_:for:)
returned. If toolbar configurations are disabled (configurations == nil
), the toolbar will auto-size to fit as many annotation types from editableAnnotationTypes
as possible.
The buttons
property of the annotation toolbar is set only after toolbar sizing completes. This is required, because the toolbar size is a prerequisite for determining which buttons will actually be shown on the toolbar. If you modify the buttons
property of the annotation toolbar manually, auto-sizing might no longer yield acceptable results. In that case, you’ll have to override preferredSizeFitting(_:for:)
and manually adjust the sizing.
Appearance Customization
The annotation toolbar exposes a variety of staying hooks for either direct or UIAppearance
-based customization. See the appearance styling guide for additional information.
Setting the toolbarDelegate of the FlexibleToolbar
The toolbarDelegate
of the FlexibleToolbar
isn’t used by PSPDFKit and can be set freely.
The easiest way to do this is to access the annotation toolbar via the annotation toolbar controller:
let pdfController = PDFViewController(document: document) pdfController.annotationToolbarController?.annotationToolbar.toolbarDelegate = toolbarDelegate
PSPDFViewController *pdfController = [[PSPDFViewController alloc] initWithDocument:document]; pdfController.annotationToolbarController.annotationToolbar.toolbarDelegate = toolbarDelegate;
You can also create a subclass of AnnotationToolbarController
and override annotationToolbar
to set it there, or create a subclass of AnnotationToolbar
and override init(annotationStateManager:)
to set it.
Showing and Hiding the Annotation Toolbar
You can show and hide the annotation toolbar with AnnotationToolbarController
.
First you have to set the hostView
with FlexibleToolbarController.updateHostView(_:container:viewController:)
:
let pdfController = PDFViewController(document: document) pdfController.annotationToolbarController?.updateHostView(nil, container: nil, viewController: pdfController)
PSPDFViewController *pdfController = [[PSPDFViewController alloc] initWithDocument:document]; [pdfController.annotationToolbarController updateHostView:nil container:nil viewController:pdfController];
After that, you can show the toolbar with FlexibleToolbarController.showToolbar(animated:)
:
let pdfController = PDFViewController(document: document) pdfController.annotationToolbarController?.showToolbar(animated: true)
PSPDFViewController *pdfController = [[PSPDFViewController alloc] initWithDocument:document]; [pdfController.annotationToolbarController showToolbarAnimated:YES];
To hide the toolbar, use FlexibleToolbarController.hideToolbar(animated:)
:
let pdfController = PDFViewController(document: document) pdfController.annotationToolbarController?.hideToolbar(animated: true)
PSPDFViewController *pdfController = [[PSPDFViewController alloc] initWithDocument:document]; [pdfController.annotationToolbarController hideToolbarAnimated:YES];