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.