Customizing Apple Pencil Annotations on iOS
PSPDFKit for iOS offers first-class support for Apple Pencil. There are a few places where you can customize how Apple Pencil interacts with PSPDFKit:
-
ApplePencilManager
tracks the detection status of Apple Pencil and whether or not it should be used for any touch interaction. -
AnnotationStateManager
manages how touch events are handled. See the Annotation State Manager guide to learn more. -
AnnotationToolbar
can show a button that lets users enable and disable the use of Apple Pencil usingApplePencilManager
. -
For double-tap actions from
UIPencilInteraction
, see our Apple Pencil Double-Tap Actions guide.
Default Behavior
The default flow of using Apple Pencil with PSPDFKit is as follows.
Users can select an annotation tool from AnnotationToolbar
. Whenever a touch from Apple Pencil is detected, ApplePencilManager
enables Apple Pencil. This can be disabled by setting ApplePencilManager.enableOnDetection
to false
.
AnnotationStateManager
decides whether or not to allow direct (finger) touches to create annotations depending on whether or not Apple Pencil has been enabled according to ApplePencilManager.enabled
. This means that after the user starts annotating with Apple Pencil, direct touches stop creating annotations so that the user can scroll and tap with fingers as normal. This can be changed by setting the stylusMode
property.
After detecting a touch from Apple Pencil the first time, AnnotationToolbar
shows a stylus button that displays the stylus connection status. This can be disabled by setting showsApplePencilButtonAutomatically
to false
. When this button is tapped, a new ApplePencilController
initialized using SDK.shared.applePencilManager
is shown, allowing the user to stop using Apple Pencil if they prefer to annotate using fingers.
Apple Pencil Availability
There is no simple way to know whether a device supports Apple Pencil, whether the user has one, and if it is currently connected. All an app knows is that if it receives a touch event of type UITouchTypeStylus
, then an Apple Pencil was connected at that time.
PSPDFKit models the availability of Apple Pencil with the ApplePencilManager.detected
property. PSPDFKit sets this to true
whenever detecting a touch of type UITouchTypeStylus
on a page view. If your app detects a touch from Apple Pencil elsewhere, you can set this property so that PSPDFKit can show the stylus button in the annotation toolbar as soon as it appears:
let touch: UITouch = ... if touch.type == .stylus { SDK.shared.applePencilManager.detected = true }
UITouch *touch = ...
if (touch.type == UITouchTypeStylus) {
PSPDFKitGlobal.sharedInstance.applePencilManager.detected = YES;
}
Every time this property is set, the ApplePencilManager
posts PSPDFApplePencilDetectedNotification
. Note that this happens even if the value does not change.
To only show a UI element if Apple Pencil is definitely available so that it does not clutter the screen otherwise, use the following:
func someSetupMethod() { NotificationCenter.default.addObserver(self, selector: #selector(stylusDetectionChanged(notification:)), name: .PSPDFApplePencilDetected, object: ApplePencilManager.self) } @objc func stylusDetectionChanged(notification: Notification) { self.showsSomeStylusUI = SDK.shared.applePencilManager.detected }
- (void)someSetupMethod { [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(stylusDetectionChanged:) name:PSPDFApplePencilDetectedNotification object:PSPDFApplePencilManager.class]; } - (void)stylusDetectionChanged:(NSNotification *)notification { self.showsSomeStylusUI = PSPDFKitGlobal.sharedInstance.applePencilManager.detected; }
Making Apple Pencil Available Across Your Application
To get the absolute best entry point for automatic Apple Pencil detection, subclass UIApplication
and override sendEvent
:
class Application: UIApplication { override func sendEvent(_ event: UIEvent) { super.sendEvent(event) let pencilManager = SDK.shared.applePencilManager guard applePencilManager.detected == false, event.type == .touches, let touches = event.allTouches else { return } if (touches.contains { $0.type == .stylus && $0.phase == .began }) { applePencilManager.detected = true } } }
Then make sure that the application is loaded from UIKit when it starts up via writing main.swift
:
UIApplicationMain(CommandLine.argc, CommandLine.unsafeArgv, NSStringFromClass(Application.self), NSStringFromClass(AppDelegate.self))
Always Create a Particular Annotation Type with Apple Pencil
You can ensure touches with Apple Pencil always create a particular annotation type, which would be a good fit if your app does not show the annotation toolbar and focuses on one type of annotation. For example, you could set Apple Pencil touches to always draw ink. Alternatively, you could set Apple Pencil to always highlight text similar to how it’s done in Books, which you can see in the Books-like highlighting example, (PSCBooksHighlightingExample
).
First set up the annotation state manager:
let annotationStateManager = pdfController.annotationStateManager
annotationStateManager.state = .ink
annotationStateManager.stylusMode = .stylus
PSPDFAnnotationStateManager *annotationStateManager = pdfController.annotationStateManager; annotationStateManager.state = PSPDFAnnotationStringInk; annotationStateManager.stylusMode = PSPDFAnnotationStateManagerStylusModeStylus;
Make sure the user can’t change the state by disabling the annotation toolbar by removing the annotationButtonItem
, which is included by default, and disabling the menu shown on long press:
pdfController.navigationItem.setRightBarButtonItems([pdfController.thumbnailsButtonItem, pdfController.activityButtonItem /* etc. as long as this excludes annotationButtonItem */], for: .document, animated: false) pdfController.updateConfiguration { builder in builder.isCreateAnnotationMenuEnabled = false }
[pdfController.navigationItem setRightBarButtonItems:@[pdfController.thumbnailsButtonItem, pdfController.activityButtonItem /* etc. as long as this excludes annotationButtonItem */] forViewMode:PSPDFViewModeDocument animated:NO];
[pdfController updateConfigurationWithBuilder:^(PSPDFConfigurationBuilder *builder) {
builder.createAnnotationMenuEnabled = NO;
}];