TLDR: Syncfusion Flutter PDF Viewer allows filling forms in a PDF document with various form fields, such as, Text box, radio button, signature and more. We’ll learn to create a Flutter app with dependencies, loading a PDF form document, filling the data in the form fields, and sharing the filled form externally by designing a Share button.
Filling out PDF forms electronically is a way to digitize the manual process of filling out paper forms. It also streamlines data collection processes, enhances accuracy, and contributes to a more efficient and environmentally friendly approach to handling information.
Our Syncfusion Flutter PDF Viewer allows you to fill, edit, save, export, and import the AcroForm fields in a PDF document. This helps fill out job applications, registration, and medical forms. We support to fill and edit the following form fields in a PDF document,
- Text box
- Checkbox
- Radio button
- Combo box
- Signature
- List box
In this blog, we’ll see the steps to fill out a registration form with proper validations using Syncfusion Flutter PDF Viewer and share the filled PDF form externally via the platform’s share dialog.
Create a Flutter app and add dependencies
First, create a new Flutter app and add the following dart packages as dependencies in it:
- syncfusion_flutter_pdfviewer
- path_provider
- share_plus
Refer to the following code example.
dependencies:
flutter:
sdk: flutter
path_provider: ^X.X.X
share_plus: ^X.X.X
syncfusion_flutter_pdfviewer: ^X.X.X
Note: The X.X.X denotes the version of the packages.
After adding the dependencies, import the following required packages in your dart code.
import 'package:syncfusion_flutter_pdfviewer/pdfviewer.dart';
import 'package:path_provider/path_provider.dart';
import 'package:share_plus/share_plus.dart';
Fill and share a registration form using Flutter PDF Viewer
Here, we’re going to fill and share a PDF form for workshop registration using Flutter PDF Viewer by following these steps:
Step 1: Create a PdfFormFilling widget class and a PdfFormFillingState class to build and display the fillable registration PDF form in the SfPdfViewer. We’ll also create a floating Share button option to share the filled PDF form externally.
/// Represents the SfPdfViewer widget loaded with the form document.
class PdfFormFilling extends StatefulWidget {
@override
_HomePage createState() => _HomePage();
}
class _HomePage extends State<PdfFormFilling> {
final GlobalKey<SfPdfViewerState> _pdfViewerKey = GlobalKey();
final PdfViewerController _pdfViewerController = PdfViewerController();
List<PdfFormField>? _formFields;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Registration Form'),
),
body: SfPdfViewer.asset(
'assets/workshop_registration.pdf',
key: _pdfViewerKey,
controller: _pdfViewerController,
onFormFieldFocusChange: _onFormFieldFocusChange,
onDocumentLoaded: _onDocumentLoaded,
),
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
_validateAndShareFormData();
},
label: const Text('SHARE', style: TextStyle(fontSize: 20)),
icon: const Icon(Icons.share),
),
);
}
}
In this example, we used the PDF named workshop_registration, which contains the following form fields:
- Name
- Gender
- Date of Birth
- State (Coming from)
- Interested courses
- Newsletter subscription and
- Signature
Step 2: To make things easier for the users, we added a DatePicker widget to pick a date when the Date of Birth field is focused. This is done with the help of the PDF Viewer’s onFormFieldFocusChange callback, and the following code explains the same.
/// Handle focus change on the DOB field to display DatePicker.
Future<void> _onFormFieldFocusChange(
PdfFormFieldFocusChangeDetails details) async {
final PdfFormField formField = details.formField;
if (details.hasFocus) {
if (formField is PdfTextFormField && formField.name == 'dob') {
final DateTime? selectedDate = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(1950),
lastDate: DateTime.now(),
);
if (selectedDate != null) {
formField.text =
'${selectedDate.day}/${selectedDate.month}/${selectedDate.year}';
}
FocusManager.instance.primaryFocus?.unfocus();
}
}
}
Note: Like this, you can also use the onFormFieldFocusChange callback to present your widgets and messages.
Step 3: Once the required fields are filled, we must validate the data in the form fields.
Let’s use the _validateAndShareFormData( ) method to perform validation. This method is invoked in the Share floating button’s onPressed callback.
/// Perform validations on the form data filled and share them externally.
Future<void> _validateAndShareFormData() async {
final List<String> errors = <String>[];
for (final PdfFormField formField in _formFields!) {
if (formField is PdfTextFormField) {
if (formField.name == 'name') {
if (formField.text.isEmpty) {
errors.add('Name is required.');
} else if (formField.text.length < 3) {
errors.add('Name should be atleast 3 characters.');
} else if (formField.text.length > 30) {
errors.add('Name should not exceed 30 characters.');
} else if (formField.text.contains(RegExp(r'[0-9]'))) {
errors.add('Name should not contain numbers.');
} else if (formField.text
.contains(RegExp(r'[!@#$%^&*(),.?":{}|<>]'))) {
errors.add('Name should not contain special characters.');
}
}
if (formField.name == 'dob') {
if (formField.text.isEmpty) {
errors.add('Date of birth is required.');
} else if (!RegExp(r'^\d{1,2}\/\d{1,2}\/\d{4}$')
.hasMatch(formField.text)) {
errors.add('Date of birth should be in dd/mm/yyyy format.');
}
}
if (formField.name == 'email') {
if (formField.text.isEmpty) {
errors.add('Email is required.');
}
// Email regex comparison
else if (!RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$')
.hasMatch(formField.text)) {
errors.add('Email should be in correct format.');
}
}
} else if (formField is PdfListBoxFormField) {
if (formField.selectedItems == null ||
formField.selectedItems!.isEmpty) {
errors.add('Please select atleast one course.');
}
} else if (formField is PdfSignatureFormField) {
if (formField.signature == null) {
errors.add('Please sign the document.');
}
}
}
if (errors.isNotEmpty) {
await showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Error'),
content: SizedBox(
height: 100,
width: 100,
child: ListView.builder(
itemCount: errors.length,
itemBuilder: (_, int index) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Text(errors[index]),
);
},
),
),
actions: <Widget>[
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text('OK'),
),
],
);
},
);
} else {
_shareForm();
}
}
void _onDocumentLoaded(PdfDocumentLoadedDetails details) {
_formFields = _pdfViewerController.getFormFields();
}
Step 4: Finally, if the validations are passed, we can share the filled PDF form externally via the platform’s share dialog. The _shareForm( ) method has the logic to perform sharing, which is called in the _validateAndShareFormData( ) method.
Refer to the following code example.
/// Share the Form externally via the platform's share dialog.
Future<void> _shareForm() async {
List<int> savedBytes = await _pdfViewerController.saveDocument();
String dir = (await getApplicationCacheDirectory()).path;
// Save the temporary file in the cache directory.
File('$dir/workshop_registration.pdf').writeAsBytesSync(savedBytes);
List<XFile> files = [
XFile('$dir/workshop_registration.pdf', mimeType: 'application/pdf'),
];
// Share the file.
await Share.shareXFiles(files, subject: 'Form document shared successful-ly.');
// Remove the file from the cache directory.
File('$dir/workshop_registration.pdf').deleteSync();
}
Note: Before sharing the form document, it will be saved first. When the saveDocument method is called, the document will be automatically reloaded after performing the save action in the PDF Viewer. Also, the signature field will be flattened on save.
You will get the output after executing the above code examples, as shown in the following image.
References
For more details, refer to the Filling and sharing PDF form files using Flutter PDF Viewer GitHub demo and documentation.
Conclusion
Thanks for reading! You now know how to fill out forms, perform validations, and share them using Flutter PDF Viewer. Try this in your app and share your feedback in the comments below.
The new version is available for current customers from the License and Downloads page. If you still need to become a Syncfusion customer, try our 30-day free trial to check out our newest features.
You can also contact us through our support forums, support portal, or feedback portal. We are always happy to assist you!