---
title: "Display building floor plans in iOS"
canonical_url: "https://www.nutrient.io/guides/ios/samples/construction/"
md_url: "https://www.nutrient.io/guides/ios/samples/construction.md"
last_updated: "2026-05-30T02:20:01.325Z"
description: "Learn to use Nutrient for displaying building floor plans in iOS construction apps. Visit our blog for additional resources."
---

# Display building floor plans in iOS with Swift

An example showing how to configure Nutrient to display a building floor plan. Get additional resources by visiting our blog on [working with PDFs in a construction application](/blog/industry-solution-construction-ios/).

[Get Started](https://www.nutrient.io/sdk/ios/getting-started.md)

[All Samples](https://www.nutrient.io/guides/ios/samples.md)

[Download](https://www.nutrient.io/guides/ios/downloads.md)

[Launch Demo](https://www.nutrient.io/demo/)

---

```swift

//
//  Copyright © 2021-2026 PSPDFKit GmbH. All rights reserved.
//
//  The Nutrient sample applications are licensed with a modified BSD license.
//  Please see License for details. This notice may not be removed from this file.
//

import PSPDFKit
import PSPDFKitUI

/// This example uses the following Nutrient features:
/// - Viewer
/// - Annotations
/// - Indexed Search
/// - Replies
///
/// See https://www.nutrient.io/sdk/ios for the complete list of Nutrient iOS SDK’s features.

class ConstructionExample: IndustryExample {

    override init() {
        super.init()

        title = "Construction"
        contentDescription = "Shows how to configure Nutrient to display a building floor plan."
        category =.industryExamples
        priority = 5
        extendedDescription = """
        This example shows how to customize the annotation toolbar for the construction industry by adding the following custom tools:

        1. The drop pin tool — this lets the user create tasks on specific areas of the building floor plan.
        2. The file attachment tool — this lets the user attach documents to the floor plan document.
        """
        url = URL(string: "https://www.nutrient.io/blog/industry-solution-construction-ios/")!
        image = UIImage(systemName: "building.2.crop.circle")
    }

    override func invoke(with delegate: ExampleRunnerDelegate) -> UIViewController {
        return ConstructionPDFViewController(with: self)
    }
}

/// Custom PDF view controller class.
private class ConstructionPDFViewController: PDFViewController, PDFViewControllerDelegate, PDFDocumentPickerControllerDelegate {

    /// Document picker shown while adding a file annotation.
    var documentPickerController: PDFDocumentPickerController?

    /// The point where the page view is long pressed to show the menu.
    /// Used to calculate the file annotation's bounding box.
    var longPressedPoint: CGPoint?

    /// Bar button item used for showing annotation list.
    private lazy var annotationListButtonItem: UIBarButtonItem = UIBarButtonItem(image: SDK.imageNamed("document_annotations")!, style: outlineButtonItem.style, target: outlineButtonItem.target, action: outlineButtonItem.action)

    /// Used for showing the more info alert.
    private var moreInfo: MoreInfoCoordinator!

    init(with example: IndustryExample) {
        let document = AssetLoader.writableDocument(for:.floorPlan, overrideIfExists: false)
        document.title = "Building Floor Plan"
        document.overrideClass(StampAnnotation.self, with: PinStampAnnotation.self)

        let emailConfiguration = DocumentSharingConfiguration.defaultConfiguration(forDestination:.email).configurationUpdated {
            $0.destination =.email
            $0.fileFormatOptions = [.PDF,.image]
            $0.annotationOptions = [.embed,.remove]
            $0.pageSelectionOptions = [.all]
        }

        let configuration = PDFConfiguration {
            // Register the custom subclass of `AnnotationToolbar` to customize the annotation toolbar.
            $0.overrideClass(AnnotationToolbar.self, with: ConstructionAnnotationToolbar.self)

            // Customize the sharing experience if available.
            if MFMailComposeViewController.canSendMail() {
                $0.sharingConfigurations = [emailConfiguration]
            }

            // Miscellaneous configuration options.
            $0.backgroundColor = UIColor.psc_secondarySystemBackground
            $0.thumbnailBarMode =.none
            $0.spreadFitting =.fit
            $0.isPageLabelEnabled = false
            $0.documentLabelEnabled =.NO
            $0.isTextSelectionEnabled = false

            // We handle the navigation bar title manually.
            $0.allowToolbarTitleChange = false
        }

        super.init(document: document, configuration: configuration)

        moreInfo = MoreInfoCoordinator(with: example, presentationContext: self)
        delegate = self

        documentPickerController = PDFDocumentPickerController(directory: "/Bundle/Samples", includeSubdirectories: true, library: SDK.shared.library)
        documentPickerController?.delegate = self

        // Configure custom default color presets.
        // See https://www.nutrient.io/guides/ios/annotations/customizing-presets/ for more details.
        let presets = [
            ColorPreset(color:.red),
            ColorPreset(color:.black),
            ColorPreset(color:.green),
            ColorPreset(color:.blue)
        ]
        setDefault(colorPresets: presets, defaultColor:.red)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override init(document: Document?, configuration: PDFConfiguration?) {
        super.init(document: document, configuration: configuration)
        moreInfo = MoreInfoCoordinator(with: ConstructionExample(), presentationContext: self)
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        // Customize the navigation bar.
        // See https://www.nutrient.io/guides/ios/user-interface/main-toolbar for more details.
        navigationItem.leftBarButtonItems = [moreInfo.barButton, toggleAnnotationVisibilityBarButtonItem]
        navigationItem.leftItemsSupplementBackButton = true

        // Only show the annotations list in the document info.
        // See https://www.nutrient.io/guides/ios/customizing-the-interface/customizing-the-available-document-information/ for more details.
        documentInfoCoordinator.availableControllerOptions = [.annotations]

        // Only support the right position for the annotation toolbar.
        let annotationToolbar = annotationToolbarController!.annotationToolbar
        annotationToolbar.supportedToolbarPositions =.right
        annotationToolbar.toolbarPosition =.right
        annotationToolbar.isDragEnabled = false

        // Use white buttons and a black background for the annotation toolbar.
        if #available(iOS 26, *) {

            // On iOS 26 we need to set the bar tint color which tints the glass background.
            annotationToolbar.barTintColor = UIColor(white: 0.2, alpha: 0.98)
        } else {
            // On older iOS versions we use the UIAppearance API
            // (which doesn't do anything anymore on iOS 26).
            let appearance = UIToolbarAppearance()
            appearance.backgroundColor = UIColor(white: 0.2, alpha: 0.98)
            annotationToolbar.standardAppearance = appearance
            annotationToolbar.compactAppearance = appearance
        }
        annotationToolbar.tintColor = UIColor(white: 0.95, alpha: 0.98)

        // Setup a tap gesture recognizer that adds a pin annotation to the page if the pin annotation tool is selected.
        let addPinAnnotationGestureRecognizer = UITapGestureRecognizer()
        addPinAnnotationGestureRecognizer.addTarget(self, action: #selector(addPinAnnotationGestureRecognizerDidChangeState))

        // Make it work simultaneously with all built-in interaction components.
        interactions.allInteractions.allowSimultaneousRecognition(with: addPinAnnotationGestureRecognizer)
        // Add the gesture recognizer to the document view controller's view.
        documentViewController?.view.addGestureRecognizer(addPinAnnotationGestureRecognizer)

        setUpdateSettingsForBoundsChange { [weak self] _ in
            self?.updateNavigationBar()
        }
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        updateNavigationBar()
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        moreInfo.showAlertIfNeeded()
    }

    // MARK: Customization

    private func updateNavigationBar() {
        let availableWidth = view.bounds.inset(by: view.safeAreaInsets).width

        // Show more items on wide screens. 440 is the minimum width needed to show 6 items including the back button.
        // Hide the title in the navigation bar if space is constrained and enable the floating document label in the document.
        if availableWidth > 440 {
            navigationItem.rightBarButtonItems = [activityButtonItem, annotationButtonItem, annotationListButtonItem]
            updateConfiguration {
                $0.documentLabelEnabled =.NO
            }
            navigationItem.title = document?.title
        } else {
            navigationItem.rightBarButtonItems = [annotationButtonItem, annotationListButtonItem]
            updateConfiguration {
                $0.documentLabelEnabled =.YES
            }
            navigationItem.title = nil
        }
    }

    // MARK: FlexibleToolbarContainerDelegate

    override func flexibleToolbarContainerWillShow(_ container: FlexibleToolbarContainer) {
        // If the annotations visibility is disabled, we force enable it when annotation toolbar becomes visible.
        if toggleAnnotationVisibilityBarButtonItem.title == "show" {
            didTapToggleAnnotationVisibilityBarButtonItem(toggleAnnotationVisibilityBarButtonItem)
        }
    }

    override func flexibleToolbarContainerDidHide(_ container: FlexibleToolbarContainer) {
        if let annotationToolbar = annotationToolbarController?.annotationToolbar as? ConstructionAnnotationToolbar {
            annotationToolbar.deselectAllTools()
        }
    }

    override func flexibleToolbarContainerContentRect(_ container: FlexibleToolbarContainer, for position: FlexibleToolbar.Position) -> CGRect {
        if [.pad,.mac].contains(container.traitCollection.userInterfaceIdiom) {
            let estimatedHeight: CGFloat = container.traitCollection.userInterfaceIdiom ==.pad? 600 : 456
            let safeArea = view.bounds.inset(by: view.safeAreaInsets).inset(by: UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20))
            return CGRect(x: safeArea.minX, y: safeArea.minY, width: safeArea.width, height: min(estimatedHeight, safeArea.height))
        } else {
            return super.flexibleToolbarContainerContentRect(container, for: position)
        }
    }

    // MARK: Private

    private lazy var toggleAnnotationVisibilityBarButtonItem: UIBarButtonItem = {
        let toggleAnnotationVisibility = UIBarButtonItem(image: UIImage(namedInCatalog: "hide"), style:.plain, target: self, action: #selector(didTapToggleAnnotationVisibilityBarButtonItem))

        toggleAnnotationVisibility.title = "hide"
        return toggleAnnotationVisibility
    }()

    @objc func didTapToggleAnnotationVisibilityBarButtonItem(_ sender: UIBarButtonItem) {
        // Let link annotations be always visible.
        if sender.title == "hide" {
            setVisibleAnnotationTypes(.link)
            sender.title = "show"
            sender.image = UIImage(namedInCatalog: "show")
        } else {
            setVisibleAnnotationTypes(.all)
            sender.title = "hide"
            sender.image = UIImage(namedInCatalog: "hide")
        }
    }

    private func setVisibleAnnotationTypes(_ types: Annotation.Kind) {
        // Update the render types.
        document?.renderAnnotationTypes = types
        // Clear the cache so that pages are re-rendered once updated.
        PSPDFKit.SDK.shared.cache.remove(for: document)
        for pageView in visiblePageViews {
            pageView.updateAnnotationViews(animated: false)
            pageView.update()
        }
    }

    private func setDefault(colorPresets: [ColorPreset]?, defaultColor: UIColor?) {
        let line = Annotation.ToolVariantID(tool:.line)
        let arrow = Annotation.ToolVariantID(tool:.line, variant:.lineArrow)
        let ink = Annotation.ToolVariantID(tool:.ink)
        let circle = Annotation.ToolVariantID(tool:.circle)
        let square = Annotation.ToolVariantID(tool:.square)
        let cloudyCircle = Annotation.ToolVariantID(tool:.circle, variant: Annotation.Variant(rawValue: "Cloudy Ellipse"))
        let dashedCircle = Annotation.ToolVariantID(tool:.circle, variant: Annotation.Variant(rawValue: "Dashed Ellipse"))
        let cloudyRectangle = Annotation.ToolVariantID(tool:.square, variant: Annotation.Variant(rawValue: "Cloudy Rectangle"))
        let dashedRectangle = Annotation.ToolVariantID(tool:.square, variant: Annotation.Variant(rawValue: "Dashed Rectangle"))
        let freeText = Annotation.ToolVariantID(tool:.freeText)
        let freeTextCallout = Annotation.ToolVariantID(tool:.freeText, variant:.freeTextCallout)

        let styleManager = SDK.shared.styleManager
        styleManager.setDefaultPresets(colorPresets, forKey: line, type:.colorPreset)
        styleManager.setDefaultPresets(colorPresets, forKey: arrow, type:.colorPreset)
        styleManager.setDefaultPresets(colorPresets, forKey: ink, type:.colorPreset)
        styleManager.setDefaultPresets(colorPresets, forKey: circle, type:.colorPreset)
        styleManager.setDefaultPresets(colorPresets, forKey: square, type:.colorPreset)
        styleManager.setDefaultPresets(colorPresets, forKey: cloudyCircle, type:.colorPreset)
        styleManager.setDefaultPresets(colorPresets, forKey: dashedCircle, type:.colorPreset)
        styleManager.setDefaultPresets(colorPresets, forKey: cloudyRectangle, type:.colorPreset)
        styleManager.setDefaultPresets(colorPresets, forKey: dashedRectangle, type:.colorPreset)
        styleManager.setDefaultPresets(colorPresets, forKey: freeText, type:.colorPreset)
        styleManager.setDefaultPresets(colorPresets, forKey: freeTextCallout, type:.colorPreset)

        // Set the default color for all the tools in the annotation toolbar.
        // See https://www.nutrient.io/guides/ios/annotations/changing-default-values-for-color-and-text-size-of-annotations/ for more details.
        styleManager.setLastUsedValue(defaultColor, forProperty: "color", forKey: line)
        styleManager.setLastUsedValue(defaultColor, forProperty: "color", forKey: arrow)
        styleManager.setLastUsedValue(defaultColor, forProperty: "color", forKey: ink)
        styleManager.setLastUsedValue(defaultColor, forProperty: "color", forKey: circle)
        styleManager.setLastUsedValue(defaultColor, forProperty: "color", forKey: square)
        styleManager.setLastUsedValue(defaultColor, forProperty: "color", forKey: cloudyCircle)
        styleManager.setLastUsedValue(defaultColor, forProperty: "color", forKey: dashedCircle)
        styleManager.setLastUsedValue(defaultColor, forProperty: "color", forKey: cloudyRectangle)
        styleManager.setLastUsedValue(defaultColor, forProperty: "color", forKey: dashedRectangle)
        styleManager.setLastUsedValue(defaultColor, forProperty: "color", forKey: freeText)
        styleManager.setLastUsedValue(defaultColor, forProperty: "color", forKey: freeTextCallout)
    }

    // MARK: Gesture recognizer action.

    @objc func addPinAnnotationGestureRecognizerDidChangeState(_ gestureRecognizer: UITapGestureRecognizer) {
        guard gestureRecognizer.state ==.ended,
           let annotationToolbar = annotationToolbarController?.annotationToolbar as? ConstructionAnnotationToolbar,
           annotationToolbar.pinStampButton.isSelected,
           let documentViewController,
           let pageView = documentViewController.visiblePageView(at: gestureRecognizer.location(in: documentViewController.view)) else {
            // Return since we do not want to add a pin stamp in this case.
            return
        }

        let viewPoint = gestureRecognizer.location(in: pageView)

        // Don't create overlapping pins.
        if (pageView.annotationSelectionView?.bounds.contains(viewPoint))!= nil {
            return
        }

        // Convert the point to PDF coordinates.
        // See https://www.nutrient.io/guides/ios/faq/coordinate-spaces/ for more details.
        let pdfPoint = pageView.convert(viewPoint, to: pageView.pdfCoordinateSpace)

        // Programmatically create the pin stamp annotation and add it to the document.
        // See https://www.nutrient.io/guides/ios/annotations/programmatically-creating-annotations/#stamp-annotations for more details.

        let pinDropURL = Bundle(for: ConstructionPDFViewController.self).resourceURL!.appendingPathComponent("pin_drop_red.pdf")
        let pinStamp = PinStampAnnotation()
        pinStamp.boundingBox = CGRect(origin: pdfPoint, size: CGSize(width: 32, height: 32))
        pinStamp.appearanceStreamGenerator = FileAppearanceStreamGenerator(fileURL: pinDropURL)
        pinStamp.pageIndex = pageIndex

        // Store custom data to distinguish between a pin stamp and a regular stamp annotation.
        // See https://www.nutrient.io/guides/ios/annotations/custom-data-in-annotations/#storing-custom-data for more details.

        pinStamp.customData = ["isPinStampAnnotation": true]

        let formatter = DateFormatter()
        formatter.timeStyle =.short
        formatter.dateStyle =.short
        pinStamp.contents = "Created on \(formatter.string(from: Date()))"
        document?.add(annotations: [pinStamp])

        // Present the note annotation view controller immediately.
        let noteAnnotationViewController = NoteAnnotationViewController(annotation: pinStamp)
        noteAnnotationViewController.modalPresentationStyle =.popover
        pageView.selectedAnnotations = [pinStamp]
        let annotationView = pageView.annotationView(for: pinStamp)
        present(noteAnnotationViewController, options: [.closeButton: true], animated: true, sender: annotationView)
    }

    // MARK: - PDFViewControllerDelegate

    func pdfViewController(_ pdfController: PDFViewController, shouldShow controller: UIViewController, options: [String: Any]? = nil, animated: Bool) -> Bool {
        if controller.isKind(of: StampViewController.self) {
            return false
        }
        return true
    }

    func pdfViewController(_ sender: PDFViewController, menuForAnnotations annotations: [Annotation], onPageView pageView: PDFPageView, appearance: EditMenuAppearance, suggestedMenu: UIMenu) -> UIMenu {
        // Keep only Comments, Delete, Inspector and Preview File actions.
        suggestedMenu.keep(actions: [.PSPDFKit.comments,.PSPDFKit.delete,.PSPDFKit.inspector,.PSPDFKit.previewFile])
    }

    func pdfViewController(_ sender: PDFViewController, menuForCreatingAnnotationAt point: CGPoint, onPageView pageView: PDFPageView, appearance: EditMenuAppearance, suggestedMenu: UIMenu) -> UIMenu {
        let attachFileAction = UIAction(title: "Attach File", image: UIImage(systemName: "paperclip")) { [self] _ in
            // Store the long pressed point in PDF coordinates to be used to set
            // the bounding box of the newly created file annotation.
            longPressedPoint = pageView.pdfCoordinateSpace.convert(point, from: pageView)
            // Present the document picker.
            present(self.documentPickerController!, options: [.closeButton: true], animated: true, sender: nil)
        }
        // Keep only the Paste action and prepend our custom action.
        return suggestedMenu.keep(actions: [.paste]).prepend([attachFileAction])
    }

    func pdfViewControllerDidDismiss(_ pdfController: PDFViewController) {
        // Restore default presets to not affect other examples.
        setDefault(colorPresets: nil, defaultColor: nil)
    }

    // MARK: - PDFDocumentPickerControllerDelegate

    func documentPickerController(_ controller: PDFDocumentPickerController, didSelect document: Document, pageIndex: PageIndex, search searchString: String?) {
        let fileURL = document.fileURL
        let fileDescription = document.fileURL?.lastPathComponent

        // Create the file annotation and its embedded file
        let fileAnnotation = FileAnnotation()
        fileAnnotation.pageIndex = pageIndex
        fileAnnotation.boundingBox = CGRect(x: (self.longPressedPoint?.x)!, y: (self.longPressedPoint?.y)!, width: 32, height: 32)
        let embeddedFile = EmbeddedFile(fileURL: fileURL!, fileDescription: fileDescription)
        fileAnnotation.embeddedFile = embeddedFile

        // Add the embedded file to the document.
        self.document?.add(annotations: [fileAnnotation])
        // Dismiss the document picker.
        controller.dismiss(animated: true, completion: nil)
    }
}

/// Custom annotation toolbar class to allow the annotation toolbar customization.
/// See https://www.nutrient.io/guides/ios/customizing-the-interface/customizing-the-annotation-toolbar/ for more details.
private class ConstructionAnnotationToolbar: AnnotationToolbar {

    public var pinStampButton: ToolbarSelectableButton = ToolbarSelectableButton()

    override init(annotationStateManager: AnnotationStateManager) {
        super.init(annotationStateManager: annotationStateManager)

        typealias Item = AnnotationToolConfiguration.ToolItem
        typealias Group = AnnotationToolConfiguration.ToolGroup

        let image = Item(type:.image)
        let ink = Item(type:.ink)

        let distance = Item(type:.line, variant:.distanceMeasurement) { _, _, _ in
            SDK.imageNamed("line_distancemeasurement")!.withRenderingMode(.alwaysTemplate)
        }
        let perimeter = Item(type:.polyLine, variant:.perimeterMeasurement) { _, _, _ in
            SDK.imageNamed("polyline_perimetermeasurement")!.withRenderingMode(.alwaysTemplate)
        }
        let ellipticalArea = Item(type:.circle, variant:.ellipticalAreaMeasurement) { _, _, _ in
            SDK.imageNamed("circle_ellipticalareameasurement")!.withRenderingMode(.alwaysTemplate)
        }
        let rectangularArea = Item(type:.square, variant:.rectangularAreaMeasurement) { _, _, _ in
            SDK.imageNamed("square_rectangularareameasurement")!.withRenderingMode(.alwaysTemplate)
        }
        let polygonArea = Item(type:.polygon, variant:.polygonalAreaMeasurement) { _, _, _ in
            SDK.imageNamed("polygon_polygonalareameasurement")!.withRenderingMode(.alwaysTemplate)
        }

        let circle = Item(type:.circle)
        let cloudyCircle = Item(type:.circle, variant: Annotation.Variant(rawValue: "Cloudy Ellipse")) { _, _, _ in
            UIImage(namedInCatalog: "ellipse_cloudy")!
        }
        let dashedCircle = Item(type:.circle, variant: Annotation.Variant(rawValue: "Dashed Ellipse")) { _, _, _ in
            UIImage(namedInCatalog: "ellipse_dashed")!
        }
        let square = Item(type:.square)
        let cloudySquare = Item(type:.square, variant: Annotation.Variant(rawValue: "Cloudy Rectangle")) { _, _, _ in
            UIImage(namedInCatalog: "rectangle_cloudy")!
        }
        let dashedSquare = Item(type:.square, variant: Annotation.Variant(rawValue: "Dashed Rectangle")) { _, _, _ in
            UIImage(namedInCatalog: "rectangle_dashed")!
        }

        let line = Item(type:.line)
        let arrow = Item(type:.line, variant:.lineArrow, configurationBlock: Item.lineConfigurationBlock())

        let freeText = Item(type:.freeText)
        let freeTextCallout = Item(type:.freeText, variant:.freeTextCallout) {_, _, _ in
            return SDK.imageNamed("freetext_callout")!.withRenderingMode(.alwaysTemplate)
        }

        let note = Item(type:.note)
        let selectionTool = Item(type:.selectionTool)

        let compactGroups = [
            Group(items: [distance, perimeter, line, arrow, ink, freeText, freeTextCallout, note]),
            Group(items: [cloudySquare, cloudyCircle, dashedSquare, dashedCircle, polygonArea, ellipticalArea, rectangularArea, square, circle]),
            Group(items: [selectionTool]),
            Group(items: [image])
        ]

        let compactConfiguration = AnnotationToolConfiguration(annotationGroups: compactGroups)

        let regularGroups = [
            Group(items: [line, arrow, ink]),
            Group(items: [distance, perimeter, polygonArea, ellipticalArea, rectangularArea]),
            Group(items: [cloudySquare, cloudyCircle, dashedSquare, dashedCircle, square, circle]),
            Group(items: [freeText, freeTextCallout, note]),
            Group(items: [selectionTool]),
            Group(items: [image])
        ]
        let regularConfiguration = AnnotationToolConfiguration(annotationGroups: regularGroups)

        configurations = [compactConfiguration, regularConfiguration]

        let fileAnnotationButton = ToolbarButton()
        fileAnnotationButton.accessibilityLabel = "Attach File"
        fileAnnotationButton.image = SDK.imageNamed("document_attachments")!.withRenderingMode(.alwaysTemplate)
        fileAnnotationButton.addTarget(self, action: #selector(fileAnnotationButtonButtonPressed(_:)), for:.touchUpInside)

        pinStampButton.accessibilityLabel = "Add Pin"
        pinStampButton.image = UIImage(namedInCatalog: "pin_drop")!.withRenderingMode(.alwaysTemplate)
        pinStampButton.addTarget(self, action: #selector(pinStampButtonButtonPressed(_:)), for:.touchUpInside)

        pinStampButton.highlightsSelection = true
        self.additionalButtons = [pinStampButton, fileAnnotationButton]
    }

    override func annotationStateManager(_ manager: AnnotationStateManager, didChangeState oldState: Annotation.Tool?, to newState: Annotation.Tool?, variant oldVariant: Annotation.Variant?, to newVariant: Annotation.Variant?) {
        if newState ==.square || newState ==.circle {
            // Update the annotation state manager's border effect property when the variant changes.
            if let variantValue = newVariant?.rawValue {
                if variantValue.hasPrefix("Cloudy") {
                    // The border effect intensity needs to be non-zero when using the cloudy border effect.
                    manager.borderEffectIntensity = 1
                    manager.borderEffect =.cloudy
                } else if variantValue.hasPrefix("Dashed") {
                    manager.borderEffectIntensity = 0
                    manager.borderEffect =.noEffect
                    manager.dashArray = [2]
                }
            } else {
                manager.borderEffectIntensity = 0
                manager.borderEffect =.noEffect
                manager.dashArray = nil
            }
        }

        // Deselect the custom pin button when changing the state.
        pinStampButton.setSelected(false, animated: true)
        super.annotationStateManager(manager, didChangeState: oldState, to: newState, variant: oldVariant, to: newVariant)
    }

    override func done(_ sender: Any?) {
        super.done(sender)

        // Deselect the custom pin button when closing the annotation toolbar.
        deselectAllTools()
    }

    public func deselectAllTools() {
        // Deselect any previously selected tool in the annotation toolbar.
        annotationStateManager.state = nil
        pinStampButton.setSelected(false, animated: false)
    }

    // MARK: Custom annotation toolbar buttons actions.

    @objc func pinStampButtonButtonPressed(_ sender: ToolbarSelectableButton) {
        // Deselect any previously selected tool in the annotation toolbar.
        annotationStateManager.state = nil
        sender.setSelected(!sender.isSelected, animated: true)
    }

    @objc func fileAnnotationButtonButtonPressed(_ sender: ToolbarButton) {
        // Deselect any previously selected tool in the annotation toolbar.
        annotationStateManager.state = nil
        pinStampButton.setSelected(false, animated: true)

        let pdfController = annotationStateManager.pdfController as! ConstructionPDFViewController
        let pageSize = pdfController.document?.pageInfoForPage(at: 0)?.size
        pdfController.longPressedPoint = CGPoint(x: pageSize!.width / 2, y: pageSize!.height / 2)
        pdfController.present(pdfController.documentPickerController!, options: [.closeButton: true], animated: true, sender: nil)
    }
}

// Hide the note icon for the pin stamp annotation.
// See https://www.nutrient.io/guides/ios/annotations/customize-annotation-rendering/#customize-or-hide-the-note-icon for more details.

private class PinStampAnnotation: StampAnnotation {
    override var shouldDrawNoteIconIfNeeded: Bool {
        let isPinStampAnnotation = customData?["isPinStampAnnotation"] as? Bool?? false
        if isPinStampAnnotation {
            return false
        } else {
            return super.shouldDrawNoteIconIfNeeded
        }
    }

    override class var supportsSecureCoding: Bool {
        true
    }
}

```

This code sample is an example that illustrates how to use our SDK. Please adapt it to your specific use case.

---

## Related pages

- [Customize PDF page lables in Swift for iOS](/guides/ios/samples/custom-page-label.md)
- [Add file annotation to PDF in Swift for iOS](/guides/ios/samples/add-file-annotation-with-embedded-file.md)
- [Add a custom cloudy rectangle annotation to a PDF in Swift for iOS](/guides/ios/samples/add-custom-cloudy-rectangle.md)
- [Add an image signature to PDF in Swift for iOS](/guides/ios/samples/add-image-signature-to-pdf-programmatically.md)
- [Add an Apple Maps widget to a PDF page in Swift for iOS](/guides/ios/samples/add-map-widget-to-pdf.md)
- [Add video annotation to PDF in Swift for iOS](/guides/ios/samples/add-video-annotation-to-pdf.md)
- [Image annotations in Swift for iOS](/guides/ios/samples/annotate-images.md)
- [Add image gallery to PDF in Swift for iOS](/guides/ios/samples/add-image-gallery-to-pdf.md)
- [Add annotation buttons to PDF toolbar in Swift for iOS](/guides/ios/samples/annotation-buttons-in-navigation-bar.md)
- [Customize blend modes in stamp annotations in Swift for iOS](/guides/ios/samples/annotation-inspector-stamp-blend-mode.md)
- [Add analytics to PDF components in Swift for iOS](/guides/ios/samples/analytics.md)
- [Create an always-dark annotation toolbar in Swift for iOS](/guides/ios/samples/always-dark-annotation-toolbar.md)
- [Creating effective link annotations on iOS](/guides/ios/samples/annotations.md)
- [Maintain annotation aspect ratio in Swift](/guides/ios/samples/aspect-ratio-conserving-resizing.md)
- [Create a custom appearance stream generator in Swift for iOS](/guides/ios/samples/appearance-stream-generator.md)
- [Write PDF annotations to XFDF in Swift for iOS](/guides/ios/samples/annotations-to-xfdf.md)
- [Add copyright watermark to PDF in Swift for iOS](/guides/ios/samples/add-copyright-watermark-to-pdf.md)
- [Add text annotation to PDF in Swift for iOS](/guides/ios/samples/add-text-annotation-to-pdf.md)
- [Embed, flatten, or remove PDF annotations in Swift for iOS](/guides/ios/samples/annotation-processing.md)
- [Add calculator to PDF using JavaScript on iOS](/guides/ios/samples/calculator.md)
- [Enable auto-save in PDF using Swift for iOS](/guides/ios/samples/auto-saving-pdf.md)
- [Blur PDF page in Swift for iOS](/guides/ios/samples/blur-pdf-pages.md)
- [Programatically create PDF annotations in Swift for iOS](/guides/ios/samples/add-annotations-to-pdf-programmatically.md)
- [Using a custom annotation provider in Swift for iOS](/guides/ios/samples/annotation-provider-with-rotation.md)
- [Asynchronously sign PDF in Swift for iOS](/guides/ios/samples/asynchronous-digital-signature-in-pdf.md)
- [Embed PDFViewController as a child in iOS](/guides/ios/samples/child-view-controller.md)
- [PDFViewController controller state in Swift for iOS](/guides/ios/samples/controller-state.md)
- [Collaborating on PDFs in board meetings using Swift for iOS](/guides/ios/samples/board-meeting.md)
- [Create link annotations in PDF using Swift for iOS](/guides/ios/samples/create-link-annotation-in-pdf.md)
- [Embed Nutrient as a child view controller in Swift for iOS](/guides/ios/samples/child-view-controller-using-parent-navigation-bar.md)
- [Present a confirmation sheet for iOS annotations](/guides/ios/samples/confirm-annotation-deletion.md)
- [Prepare PDF to capture digital signature in Swift for iOS](/guides/ios/samples/contained-digital-signatures.md)
- [Prepare PDF to embed PAdES digital signature in Swift for iOS](/guides/ios/samples/contained-pades-digital-signature.md)
- [Create PDF bookmark with UI in Swift for iOS](/guides/ios/samples/create-pdf-bookmark-name-ui.md)
- [Add a custom free text input accessory in Swift for iOS](/guides/ios/samples/custom-free-text-input-accessory.md)
- [Custom annotation provider in Swift for iOS](/guides/ios/samples/custom-annotation-provider.md)
- [Create password-protected PDF in Swift for iOS](/guides/ios/samples/create-password-protected-pdf.md)
- [Continiously create free text annotations in Swift for iOS](/guides/ios/samples/create-free-text-annotations-continuously.md)
- [Aviation example: Displaying flight plan PDF in Swift for iOS](/guides/ios/samples/aviation.md)
- [Clear all PDF annotations with a button in Swift for iOS](/guides/ios/samples/custom-button-in-annotation-toolbar.md)
- [Select PDF text and create a note in Swift for iOS](/guides/ios/samples/create-note-from-selection.md)
- [Customize annotation link border color in Swift for iOS](/guides/ios/samples/custom-link-border-color.md)
- [Create PDF programmatically in Swift for iOS](/guides/ios/samples/create-pdf-programmatically.md)
- [Add custom font sizes to free text keyboard in Swift for iOS](/guides/ios/samples/custom-buttons-free-text-keyboard-toolbar.md)
- [Custom PDF bookmark provider in Swift for iOS](/guides/ios/samples/custom-pdf-bookmark-provider.md)
- [Custom Comments Ui](/guides/ios/samples/custom-comments-ui.md)
- [Use a custom image picker controller in Swift for iOS](/guides/ios/samples/custom-image-picker-controller.md)
- [Customize PDF outline in Swift for iOS](/guides/ios/samples/custom-pdf-outline-controller.md)
- [Customize PDF sharing options in Swift for iOS](/guides/ios/samples/custom-pdf-sharing-options.md)
- [Custom Thumbnail Page Label](/guides/ios/samples/custom-thumbnail-page-label.md)
- [Customize pencil interactions on PDF using Swift for iOS](/guides/ios/samples/custom-pencil-interaction-action.md)
- [Custom thumbnail PDF view filter in Swift for iOS](/guides/ios/samples/custom-thumbnail-view-controller-filter.md)
- [Customize the search result cell in Swift for iOS](/guides/ios/samples/custom-search-result-cell.md)
- [Customize PDF tab titles in Swift for iOS](/guides/ios/samples/custom-tabbed-bar-title.md)
- [Customize PDF annotation toolbar in Swift for iOS](/guides/ios/samples/customize-pdf-annotation-toolbar.md)
- [Custom PDF stamp annotation in Swift for iOS](/guides/ios/samples/custom-pdf-stamp-annotations.md)
- [Customize the filename of shared PDF in Swift for iOS](/guides/ios/samples/custom-sharing-filenames.md)
- [Customized note annotation view controller in Swift for iOS](/guides/ios/samples/customized-note-annotation-view-controller.md)
- [How to disable digital signature removal in PDFs](/guides/ios/samples/disable-removing-digital-signature.md)
- [Disable PDF annotation editing in Swift for iOS](/guides/ios/samples/disable-annotation-editing.md)
- [Disable annotations reviews in PDF using Swift for iOS](/guides/ios/samples/disable-annotation-reviews.md)
- [Display PDF in inbox directory using Swift for iOS](/guides/ios/samples/display-pdf-inbox.md)
- [Initialize a PDF with data in Swift for iOS](/guides/ios/samples/document-data-provider-pdf-from-data.md)
- [Disable bookmark editing in PDF using Swift for iOS](/guides/ios/samples/disable-bookmark-editing.md)
- [Add watermark to all PDF pages using Swift for iOS](/guides/ios/samples/draw-watermark-on-pdf-pages.md)
- [Encrypt and decrypt a PDF using Swift for iOS](/guides/ios/samples/encrypt-decrypt-pdf.md)
- [Customize the PDF search highlight color in Swift for iOS](/guides/ios/samples/custom-search-highlight-color.md)
- [Save reading position in PDF using Swift for iOS](/guides/ios/samples/document-view-state-restoration.md)
- [Disable scroll bouncing in PDF using Swift for iOS](/guides/ios/samples/disable-scroll-bouncing.md)
- [Implement a Document Picker sidebar in Swift for iOS](/guides/ios/samples/document-picker-sidebar.md)
- [Document With Original Url Set](/guides/ios/samples/document-with-original-url-set.md)
- [Encrypt disk cache when rendering PDF in Swift for iOS](/guides/ios/samples/encrypted-cache.md)
- [PDF highlight annotation blend mode menu in Swift for iOS](/guides/ios/samples/highlight-annotation-blend-mode-menu.md)
- [Fixed-sized PDF stamp annotations in Swift for iOS](/guides/ios/samples/floating-pdf-stamp-annotation.md)
- [Exit PDF drawing mode automatically in Swift for iOS](/guides/ios/samples/exit-drawing-mode-automatically.md)
- [Apply XFDF annotations and save it as new PDF in Swift for iOS](/guides/ios/samples/embedded-xfdf-annotation-provider.md)
- [Allow freeform image annotation resizing in Swift for iOS](/guides/ios/samples/freeform-image-resize.md)
- [Disable bookmark renaming in PDF using Swift for iOS](/guides/ios/samples/disable-bookmark-renaming.md)
- [Convert HTML to PDF using Swift for iOS](/guides/ios/samples/html-to-pdf.md)
- [Add video, audio, image annotation to PDF in Swift for iOS](/guides/ios/samples/gallery.md)
- [Add a bottom inset to the user interface in Swift for iOS](/guides/ios/samples/inset-user-interface.md)
- [Insert page into PDF from another document in Swift for iOS](/guides/ios/samples/insert-pdf-page-from-document.md)
- [Customize comment font size in PDF using Swift for iOS](/guides/ios/samples/large-font-for-comments.md)
- [Monitor UI touches using Swift for iOS](/guides/ios/samples/monitor-touches.md)
- [Customize PDF form appearance in Swift for iOS](/guides/ios/samples/customizing-pdf-form-appearance.md)
- [Customize the annotation selection knobs in Swift for iOS](/guides/ios/samples/custom-selection-knobs.md)
- [Customize vertical annotation toolbar in Swift for iOS](/guides/ios/samples/custom-vertical-annotation-toolbar.md)
- [Customize the annotations list in Swift for iOS](/guides/ios/samples/customizing-annotation-list.md)
- [Encrypted Xfdf Annotation Provider](/guides/ios/samples/encrypted-xfdf-annotation-provider.md)
- [Face redaction in document using Swift for iOS](/guides/ios/samples/face-redaction-in-pdf.md)
- [Draw all PDF annotations as overlays in Swift for iOS](/guides/ios/samples/draw-annotations-as-overlay.md)
- [Configuring PDF reader in Swift for iOS](/guides/ios/samples/e-reader.md)
- [Customize PDF view margins using Swift for iOS](/guides/ios/samples/dynamic-margins.md)
- [Lazy load PDF annotations in Swift for iOS](/guides/ios/samples/lazy-load-pdf-annotations.md)
- [Highlight text in PDF using Swift for iOS](/guides/ios/samples/highlight-text-in-pdf.md)
- [LMS example: Take and grade an exam using Swift for iOS](/guides/ios/samples/e-learning.md)
- [Using Instant JSON to collaborate on PDFs in Swift for iOS](/guides/ios/samples/instant-json.md)
- [Generate a PDF report using Swift for iOS](/guides/ios/samples/generate-pdf-report.md)
- [Hide or reveal an area in a PDF using Swift for iOS](/guides/ios/samples/hide-reveal-area-in-pdf.md)
- [Configuring multiline titles in PDF using Swift for iOS](/guides/ios/samples/multiline-pdf-title.md)
- [Link annotation view customization in Swift for iOS](/guides/ios/samples/link-annotation-view-customization.md)
- [OCR PDF using Swift for iOS](/guides/ios/samples/ocr-pdf.md)
- [Add overlay views to PDF in Swift for iOS](/guides/ios/samples/overlay-views.md)
- [Custom PDF page labels in the sharing UI in Swift for iOS](/guides/ios/samples/page-labels-in-sharing-ui.md)
- [Open AES-encrypted PDF in Swift for iOS](/guides/ios/samples/open-aes-encrypted-pdf.md)
- [Password Not Preset](/guides/ios/samples/password-not-preset.md)
- [Custom saving options after editing PDF in Swift for iOS](/guides/ios/samples/pdf-editor-custom-saving-confirmation.md)
- [Customize PDF editor toolbar using Swift for iOS](/guides/ios/samples/pdf-editor-toolbar-customization.md)
- [Toggle PDF form field highlight color in Swift for iOS](/guides/ios/samples/pdf-form-highlight-color.md)
- [Render drawings on PDF pages using Swift for iOS](/guides/ios/samples/pdf-page-drawing.md)
- [Custom page template in PDF editor using Swift for iOS](/guides/ios/samples/pdf-editor-custom-templates.md)
- [PDF reflow with Reader View in Swift for iOS](/guides/ios/samples/pdf-reader-view.md)
- [Create email snippet when sharing PDF in Swift for iOS](/guides/ios/samples/predefined-email-body.md)
- [Create PDF teleprompter using Swift for iOS](/guides/ios/samples/pdf-teleprompter.md)
- [Printer defaults for PDF annotations in Swift for iOS](/guides/ios/samples/printer-defaults.md)
- [Redact text in PDF using Swift for iOS](/guides/ios/samples/pdf-redaction.md)
- [Persist view settings using Swift for iOS](/guides/ios/samples/persist-view-settings.md)
- [Display PDFViewController in popover using Swift for iOS](/guides/ios/samples/popover-presentation.md)
- [Open PDF with preset password using Swift for iOS](/guides/ios/samples/preset-pdf-passwords.md)
- [Customize PDF view settings in Swift for iOS](/guides/ios/samples/pdf-view-settings.md)
- [Getting started with iOS playground](/guides/ios/samples/playground.md)
- [Programmatically edit PDFs using Swift for iOS](/guides/ios/samples/programmatic-pdf-editing.md)
- [Customize iOS annotation inspector color presets](/guides/ios/samples/preset-customization.md)
- [Download PDF from URL using Swift for iOS](/guides/ios/samples/remote-document-url.md)
- [Programmatically go to PDF outline in Swift for iOS](/guides/ios/samples/programmatically-go-to-outline.md)
- [Remove password from PDF using Swift for iOS](/guides/ios/samples/remove-pdf-password.md)
- [Rotate PDF page using Swift for iOS](/guides/ios/samples/rotate-pdf-page.md)
- [Rotate PDF pages with Swift](/guides/ios/samples/rotate-page-temporarily.md)
- [Configure PDF annotation toolbar using Swift for iOS](/guides/ios/samples/manual-toolbar-setup.md)
- [Cycle through PDF documents using Swift for iOS](/guides/ios/samples/page-view-controller.md)
- [PDF collaboration using Swift for iOS](/guides/ios/samples/pdf-collaboration.md)
- [Show PDF download progress in Swift for iOS](/guides/ios/samples/pdf-download-progress.md)
- [Compare PDF documents using Swift for iOS](/guides/ios/samples/pdf-document-comparison.md)
- [PDF magazine reader using Swift for iOS](/guides/ios/samples/pdf-magazine-reader.md)
- [PDF text redaction using regex in Swift for iOS](/guides/ios/samples/redact-pdf-text-using-regex.md)
- [PDF page scale and resize using Swift for iOS](/guides/ios/samples/pdf-page-scaling.md)
- [Auto-save PDF annotation changes in Swift for iOS](/guides/ios/samples/save-as-pdf.md)
- [Customize scrubber bar with buttons using Swift for iOS](/guides/ios/samples/scrubber-bar-with-buttons.md)
- [Programtically search a PDF using Swift for iOS](/guides/ios/samples/search-without-controller.md)
- [Enable saving confirmation when exiting PDF in Swift for iOS](/guides/ios/samples/save-confirmation.md)
- [Customize view controller for screen mirroring in Swift for iOS](/guides/ios/samples/screen-mirroring.md)
- [Search multiple PDF files using Swift for iOS](/guides/ios/samples/search-multiple-pdf-files.md)
- [Select all text in a PDF using Swift for iOS](/guides/ios/samples/select-all-pdf-text.md)
- [Select free text annotation in PDF using Swift for iOS](/guides/ios/samples/select-free-text-annotations.md)
- [Show multiple files as a single PDF using Swift for iOS](/guides/ios/samples/show-multiple-files-in-pdf.md)
- [Show note controller for highlights in Swift for iOS](/guides/ios/samples/show-note-controller-for-highlights.md)
- [Simplifying the font picker for text annotation using Swift for iOS](/guides/ios/samples/simple-font-picker.md)
- [Simplifying the annotation inspector using Swift for iOS](/guides/ios/samples/simple-annotation-inspector.md)
- [Convert stamp into a PDF button in Swift for iOS](/guides/ios/samples/stamp-button.md)
- [Create a custom PDF navigation bar with SwiftUI for iOS](/guides/ios/samples/swiftui-custom-navigation-bar.md)
- [Embed a SwiftUI view inside a page view on iOS](/guides/ios/samples/swiftui-on-page-view.md)
- [SwiftUI split screen: Display two PDF views side by side on iOS](/guides/ios/samples/swiftui-split-screen.md)
- [Enable fixed PDF toolbar position in Swift for iOS](/guides/ios/samples/top-toolbar-position.md)
- [Swiftui Sharing](/guides/ios/samples/swiftui-sharing.md)
- [Use PDFViewController with SwiftUI for iOS](/guides/ios/samples/swiftui.md)
- [Update configuration when rotating PDF in Swift for iOS](/guides/ios/samples/update-configuration-when-rotating.md)
- [Show or hide PDF annotations using Swift for iOS](/guides/ios/samples/toggle-annotation-visibility.md)
- [Multi-user PDF collaboration using Swift for iOS](/guides/ios/samples/multi-user-pdf-collaboration.md)
- [Convert MS Office (DOCX, XLSX, PPTX) to PDF in Swift for iOS](/guides/ios/samples/office-to-pdf-conversion.md)
- [Display measurements on PDF pages or spreads in Swift for iOS](/guides/ios/samples/measurements-on-pages-spreads.md)
- [Search and redact text in a PDF using Swift for iOS](/guides/ios/samples/search-and-redact-pdf-text.md)
- [Show author name on annotation selection in Swift for iOS](/guides/ios/samples/show-author-name-on-annotation-selection.md)
- [Programmatically add a signature to all PDF pages using Swift for iOS](/guides/ios/samples/sign-all-pdf-pages.md)
- [Store PDF annotations for multiple users in Swift for iOS](/guides/ios/samples/store-multiple-user-annotations.md)
- [PDF streaming using Swift for iOS](/guides/ios/samples/streaming-pdf.md)
- [Sticky header for PDF thumbnail view in Swift for iOS](/guides/ios/samples/sticky-header.md)
- [PDF streaming with SwiftUI for iOS](/guides/ios/samples/streaming-pdf-swiftui.md)
- [Create a custom PDF page setting view in SwiftUI for iOS](/guides/ios/samples/swiftui-settings.md)
- [Customize PDF annotation toolbar with SwiftUI for iOS](/guides/ios/samples/swiftui-annotationt-toolbar.md)
- [Custom annotation inspector with SwiftUI for iOS](/guides/ios/samples/swiftui-custom-annotation-inspector.md)
- [Import and export annotations in XFDF using Swift for iOS](/guides/ios/samples/xfdf-annotation-provider.md)
- [Add SwiftUI sidebar next to PDF view on iOS](/guides/ios/samples/swiftui-sidebar.md)
- [Show multiple PDFs with tabbed UI using Swift for iOS](/guides/ios/samples/tabbed-bar.md)
- [Add a snake game inside a PDF in Swift for iOS](/guides/ios/samples/snake.md)
- [Integrate UIStoryboard with PDFViewController in Swift for iOS](/guides/ios/samples/storyboard.md)
- [Display PDF annotations on layers in Swift for iOS](/guides/ios/samples/pdf-annotation-layers.md)
- [PDF form examples using Swift for iOS](/guides/ios/samples/pdf-forms.md)

