Blog Post

Creating and Filling Forms Programmatically in Swift

Illustration: Creating and Filling Forms Programmatically in Swift

Forms are a common feature in PDF files used to interactively collect and submit data from users. AcroForms (short for Acrobat Forms) were introduced in the PDF 1.2 format specification and support interactive form objects such as text boxes, radio buttons, combo boxes, and signatures. They also permit the use of JavaScript to react to user input, as JavaScript is often used for input validation. PSPDFKit for iOS fully supports the AcroForm standard, and forms can be created, viewed, and filled inside PDFViewController.

In this blog post, we’ll show how to create form elements in an empty PDF file and how to programmatically fill them using Swift. We’ll be using PSPDFKit APIs to perform these tasks, so this post assumes you have basic knowledge of how to get PSPDFKit up and running. If not, you can check out our getting started guides.

Form Field and Annotation Objects

Before we start adding form elements to a PDF page, let’s take some time to understand two different types of form objects: field objects and annotation objects. Form field objects keep track of the state of a form field and can be identified by their fullyQualifiedName. Form annotation objects provide a graphical element on top of the form field object. Each form field object has one or more annotation objects attached to it.

Here’s a list of the form field and annotation objects for each different form input type:

Type Field Object Annotation Object
Check, Radio, and Push Buttons ButtonFormField ButtonFormElement
List and Combo Boxes ChoiceFormField ChoiceFormElement
Text TextFormField TextFieldFormElement
Digital Signatures SignatureFormField SignatureFormElement

You can find more information about forms in our Introduction to Forms guide.

Creating Forms

Now that we have the background information about form elements, let’s see how to add them to a PDF file. We’ll add one form input of each type: radio button, list box, text input, and digital signature.

Radio Button

// Add a radio button with two options.
let radio1 = ButtonFormElement()
let radio2 = ButtonFormElement()

// Position and add it to the first page.
radio1.boundingBox = CGRect(x: 100, y: 300, width: 20, height: 20)
radio1.pageIndex = 0
radio2.boundingBox = CGRect(x: 130, y: 300, width: 20, height: 20)
radio2.pageIndex = 0

// The `buttonValues` specify the radio buttons' `onState` value.
let buttonValues = ["RadioButton1", "RadioButton2"]
let radioButtonFormField = try! ButtonFormField.insertedButtonField(with: .radioButton, fullyQualifiedName: "Radio Button", documentProvider: documentProvider, formElements: [radio1, radio2], buttonValues: buttonValues)

List Box

// Add a list box with two options.
let listBoxFormElement = ChoiceFormElement()
// Position and add it to the first page.
listBoxFormElement.boundingBox = CGRect(x: 100, y: 400, width: 200, height: 50)
listBoxFormElement.pageIndex = 0
// Insert a form field for the form element.
let listBoxFormField = try! ChoiceFormField.insertedChoiceField(with: .listBox, fullyQualifiedName: "List Box", documentProvider: documentProvider, formElement: listBoxFormElement)
// Update the options for the form field.
listBoxFormField.options = [
    PDFFormOption(label: "Option 1", value: "Option 1"),
    PDFFormOption(label: "Option 2", value: "Option 2")
]

Text Input

// Create a new text field form element.
let textFieldFormElement = TextFieldFormElement()
// Position and add it to the first page.
textFieldFormElement.boundingBox = CGRect(x: 100, y: 500, width: 200, height: 40)
textFieldFormElement.pageIndex = 0
// Insert a form field for the form element.
let textFormField = try! TextFormField.insertedTextField(withFullyQualifiedName: "Text Form Field", documentProvider: documentProvider, formElement: textFieldFormElement)

Digital Signature

// Create a new signature form element.
let signatureFormElement = SignatureFormElement()
// Position and add it to the first page.
signatureFormElement.boundingBox = CGRect(x: 100, y: 600, width: 100, height: 40)
signatureFormElement.pageIndex = 0
// Insert a form field for the form element.
let signatureFormField = try! SignatureFormField.insertedSignatureField(withFullyQualifiedName: "Digital Signature", documentProvider: documentProvider, formElement: signatureFormElement)

Once we have a PDF file with form fields, we can find and remove the fields using PSPDFFormParser. We can use the following methods to find and remove form fields, respectively:

Programmatically Filling Forms

Now we can use PSPDFFormParser to fetch the form field we’re interested in, and then we can fill it programmatically however we wish. In this section, we’ll go through the process of programmatically filling three of the four types of form fields that we added earlier: radio buttons, list boxes, and text inputs. For digital signatures, we have a guide that explains all the intricacies of adding a digital signature.

Radio Button

// Fetch the document's form parser.
guard let parser = document.formParser else { return }

// Find the radio button form field with name: "Radio Button."
let radioButtonFormField = parser.findField(withFullFieldName: "Radio Button") as! ButtonFormField

// Loop through the annotations attached to the form field.
for annotation in radioButtonFormField.annotations {
    guard let buttonFormElement = annotation as? ButtonFormElement else { continue }
    guard let text = buttonFormElement.onState else { continue }

    // Select the radio button with text = "RadioButton2."
    if text == "RadioButton2" {
        radioButtonFormField.selectedAnnotationObjectNumbers = [NSNumber(value: buttonFormElement.objectNumber)]
    }
}

List Box

// Find the list box with name: "List Box."
let listBoxFormField = parser.findField(withFullFieldName: "List Box") as! ChoiceFormField

// `IndexSet` used to store the list of indices we want to select.
var selectedIndices = IndexSet()

// Loop through the list box options and find "Option 2."
for (index, option) in listBoxFormField.options.enumerated() where option.value == "Option 2" {
    selectedIndices.insert(index)
}

// Update the `selectedIndices` property of the list box.
listBoxFormField.selectedIndices = selectedIndices

Text Input

// Find the text form field with name: "Text Form Field."
let textFormField = parser.findField(withFullFieldName: "Text Form Field") as! TextFormField

// Update the text.
textFormField.text = "Programmatically filled text."

After filling a form, the data in it can be submitted to different destinations in a variety of different formats. Our Form Submission guide explains this process in detail.

Conclusion

In this blog post, we talked about how to create and fill forms programmatically using PSPDFKit for iOS. To see more examples and code samples related to forms, check out the Forms and Digital Signatures section of our example app in the Catalog project. If you have any questions regarding forms, please don’t hesitate to reach out to us.

Related Products
Share Post

Related Articles

Explore more
DEVELOPMENT  |  iOS • Development • How To

Automating Mac Catalyst Distribution with fastlane

RELEASES  |  iOS • Products

PSPDFKit 10.4 for iOS Introduces an Overhauled Undo Architecture

TUTORIALS  |  iOS • Development • How To • Swift

Adding Annotations in Swift with PDFKit vs. PSPDFKit