Create fillable PDF forms on Android

In Nutrient 4.4, we added support for programmatic form field creation in a document. This can be useful, for instance, when a PDF document needs to be digitally signed but doesn’t contain a signature field.

A form field is a model representation of a visual form in a document. To be able to create a form field, you have to first create a form element (also known as a widget annotation). This works the same as adding any other annotation, as can be seen in the guide on programmatically creating annotations, although you don’t need to explicitly add the annotation, as it’ll be added automatically when adding the form field. For more information on the difference between a form field and a form element, see our introduction to forms guide.

Check out the API reference for more regarding the Forms API.

Adding a signature form field

A form field is a model representation of a visual form element in a document. To enable form field creation, Nutrient exposes a handy set of configuration builders that make the entire process smooth. For more information on the difference between a form field and a form element, see our introduction to forms guide.

The minimum amount of information required for the creation of a signature form configuration is the page index and the annotation bounding box that will contain the signature form element. Once built, it can be added to a document using FormProvider#addFormElementToPage:

val page = 0
val rectFSignatureFormConfiguration = RectF(
    30f, // left
    190f, // top
    200f, // right
    160f // bottom
)
val signatureFormConfiguration = SignatureFormConfiguration.Builder(page, rectFSignatureFormConfiguration)
    .build()
val signatureFormField = document.formProvider.addFormElementToPage("signaturefield-1", signatureFormConfiguration)
int page = 0;
RectF rectFSignatureFormConfiguration = new RectF(
    30, // left
    190, // top
    200, // right
    160 // bottom
);
SignatureFormConfiguration signatureFormConfiguration = new SignatureFormConfiguration.Builder(page, rectFSignatureFormConfiguration)
    .build();
SignatureFormField signatureFormField = getDocument().getFormProvider().addFormElementToPage("signaturefield-1", signatureFormConfiguration);

You can add any kind of form field to a document, apart from signature form fields. Check out the Android documentation for more info about the Forms API.

Adding radio buttons and checkboxes

CheckBoxFormField and RadioButtonFormField can be made up of more than one form element. To add these form fields to a document, you can use FormProvider#addFormElementsToPage, which takes all the elements and attaches them to the newly created field:

val page = 0

val rectFRadioButtonFormConfiguration1 = RectF(
    30f, // left
    500f, // top
    60f, // right
    470f // bottom
)
val radioButtonFormConfiguration1 = RadioButtonFormConfiguration.Builder(page, rectFRadioButtonFormConfiguration1)
    .select()
    .build()

val rectFRadioButtonFormConfiguration2 = RectF(
    30f, // left
    450f, // top
    60f, // right
    420f // bottom
)

val radioButtonFormConfiguration2 = RadioButtonFormConfiguration.Builder(page, rectFRadioButtonFormConfiguration2)
    .deselect()
    .build()

val radioButtonFormConfigurationList = Arrays.asList(radioButtonFormConfiguration1, radioButtonFormConfiguration2)
val radioButtonFormField = document.formProvider.addFormElementsToPage("radiobuttonfield-1", radioButtonFormConfigurationList)
int page = 0;

RectF rectFRadioButtonFormConfiguration1 = new RectF(
    30, // left
    500, // top
    60, // right
    470 // bottom
);
RadioButtonFormConfiguration radioButtonFormConfiguration1 = new RadioButtonFormConfiguration.Builder(page, rectFRadioButtonFormConfiguration1)
    .select()
    .build();

RectF rectFRadioButtonFormConfiguration2 = new RectF(
    30, // left
    450, // top
    60, // right
    420 // bottom
);

RadioButtonFormConfiguration radioButtonFormConfiguration2 = new RadioButtonFormConfiguration.Builder(page, rectFRadioButtonFormConfiguration2)
    .deselect()
    .build();

List<RadioButtonFormConfiguration> radioButtonFormConfigurationList = Arrays.asList(radioButtonFormConfiguration1, radioButtonFormConfiguration2);
RadioButtonFormField radioButtonFormField = getDocument().getFormProvider().addFormElementsToPage("radiobuttonfield-1", radioButtonFormConfigurationList);

⚠️ Warning: FormProvider#addFormElementsToPage only supports homogeneous lists. The mixing of configuration classes of different types isn’t supported.

For more examples, check out FormCreationExample in our Catalog app.

Adding a submit button

Here’s how to add a button to submit the current values of a form in XFDF format to an HTTP endpoint. Other available formats are FDF, HTML, or the whole PDF:

override fun onDocumentLoaded(document: PdfDocument) {
    super.onDocumentLoaded(document)
    ...
    // Retrieve the form field to include in the submit form action.
    val checkBoxField = document?.formProvider?.getFormFieldWithFullyQualifiedName("checkboxfield-1")

    val rectFPushButtonFormConfiguration = RectF(30f, 350f, 120f, 260f)
    val colorBitmap = Bitmap.createBitmap(500, 300, Bitmap.Config.ARGB_8888)
    val canvas = Canvas(colorBitmap)
    // Just use a red fill so the button is visible.
    canvas.drawColor(Color.RED)

    // Create the button form element (annotation).
    val pushButtonFormConfiguration = PushButtonFormConfiguration.Builder(
        0,
        rectFPushButtonFormConfiguration,
        colorBitmap
        )
            // Create the action and set the submission format to XFDF.
            .setAction(SubmitFormAction(
                "https://example.com/wherever-you-want-to-send-the-form",
                mutableListOf(checkBoxField),
                EnumSet.of(SubmitFormAction.SubmitFormActionFlag.XFDF)))
            .build()

    // Ask PSPDFKit to create the form field and add it to the document. This will also add the form element to the document.
    // The `fullyQualifiedName` must not be the same as an existing form field, but otherwise can be whatever you like.
    document?.formProvider?.addFormElementToPage("pushbuttonfield-1", pushButtonFormConfiguration)
@UiThread
@Override
public void onDocumentLoaded(@NonNull final PdfDocument document) {
    super.onDocumentLoaded(document);
    ...
    // Retrieve the form field to include in the submit form action.
    CheckBoxField checkBoxField = document.getFormProvider().getFormFieldWithFullyQualifiedName("checkboxfield-1");

    RectF rectFPushButtonFormConfiguration = new RectF(30f, 350f, 120f, 260f);
    Bitmap colorBitmap = Bitmap.createBitmap(500, 300, Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(colorBitmap);
    // Just use a red fill so the button is visible.
    canvas.drawColor(Color.RED);

    // Create the button form element (annotation).
    PushButtonFormConfiguration pushButtonFormConfiguration = new PushButtonFormConfiguration.Builder(
        0,
        rectFPushButtonFormConfiguration,
        colorBitmap
        )
            // Create the action and set the submission format to XFDF.
            .setAction(new SubmitFormAction(
                "https://example.com/wherever-you-want-to-send-the-form",
                mutableListOf(checkBoxField),
                EnumSet.of(SubmitFormAction.SubmitFormActionFlag.XFDF)))
            .build();

    // Ask PSPDFKit to create the form field and add it to the document. This will also add the form element to the document.
    // The `fullyQualifiedName` must not be the same as an existing form field, but otherwise can be whatever you like.
    document.getFormProvider().addFormElementToPage("pushbuttonfield-1", pushButtonFormConfiguration);

ℹ️ Note: Submitting actions aren’t yet supported by Nutrient Android SDK, but they can be added so that other readers can use them. If you need to execute the created action with Nutrient Android SDK, you can find the relevant information in the customizing the submission method guide.

Removing form fields and form elements

You can remove any form field or form element from a document using AnnotationProvider. Just call either removeAnnotationFromPage(Annotation) or removeAnnotationFromPageAsync(Annotation):

document?.annotationProvider?.removeAnnotationFromPage(checkBoxField?.formElement?.annotation as Annotation)
document.getAnnotationProvider().removeAnnotationFromPage(((Annotation) checkBoxField.getFormElement().getAnnotation()));