PSPDFKit for iOS supports undo/redo for creating and editing annotations. (This includes form filling)
To achieve this, the SDK uses a standard component named
NSUndoManager. We recommend studying both Apple's Documentation and the NSHipster article to understand the principles how this class works if you never used it before.
PSPDFKit uses a
PSPDFUndoController object which wraps and manages the undo manager and allows more convenient access to properties such as
The undo controller also extends Apple's concept by adding a timed coalescing mode, which merges undo changes. This is used in various places, for example when a color is chosen from the color picker, we don't save every single change but commit the change after a short period of time to have a better undo/redo experience for the user. This implies that whenever the
PSPDFUndoController object exposes properties, you should use these and only in cases where there's no other way go down to the wrapped undo manager instance.
If you're implementing your own undo/redo buttons and are trying to update the enabled state, you need to listen for following notifications:
optional public func annotationStateManager(_ manager: PSPDFAnnotationStateManager, didChangeUndoState undoEnabled: Bool, redoState redoEnabled: Bool)
- (void)annotationStateManager:(PSPDFAnnotationStateManager *)manager didChangeUndoState:(BOOL)undoEnabled redoState:(BOOL)redoEnabled;
PSCVerticalAnnotationToolbarExample.m for a sample implementation of custom undo/redo buttons.
PSPDFKit is a good iOS citizen and supports the native ways of undoing, which on the iPhone is shake to undo. See this article in the iOS Human Interface Guidelines.. Shake to Undo can be both deactivated from the user in the phone Accessibility settings or via the
applicationSupportsShakeToEdit property on
On iPad we support the native undo button on the keyboard.
Saving annotations will clear the undo/redo stack. Writing objects into the PDF changes various details, and providing a reliable undo would be very difficult. Saving happens at various points, including when the application enters the background.
On a technical level, our undo/redo works via using KVO and registering each annotation object and tracking changes on a property-basis.