Forms are an integral part of many applications, and handling them efficiently can significantly enhance user experience. In this comprehensive guide, we will explore how to work with form within Flutter—a popular open-source UI software development toolkit. We will cover creating a form, managing its state, validating different fields, and saving form data. Additionally, we’ll implement a registration page example where users can input their email, phone number, and password. The form will only proceed when the given information is in the correct format.
If you prefer watching a video tutorial here is a link to that.
Setting Up the Project
Creating an Empty Project
To get started with our form handling app, initialize a new Flutter project. If you’ve already got Flutter installed, you can set up a new project using the command:
flutter create form_handling_example
Navigate into your project directory:
cd form_handling_example
Initializing the HomePage Widget
Creating a Stateful Widget
Inside your lib
directory, create a new Dart file named homepage.dart
. Here, define a stateful widget to represent our home page:
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Registration Page'),
),
body: buildUI(),
);
}
Widget buildUI() {
return SafeArea(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Form(
// Further implementation will come here
),
),
);
}
}
Returning an Empty Scaffold
We initialize our HomePage
widget with an empty Scaffold
which serves as a starting point for our layout.
Setting HomePage as Home in main.dart
Now, open main.dart
, and set the HomePage
widget as the home property in your MaterialApp
:
import 'package:flutter/material.dart';
import 'homepage.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
);
}
}
Building the UI
Adding an AppBar
The AppBar
is already added in the previous step to help navigate within the application. It holds the title ‘Registration Page’.
Defining the Body
Calling the buildUI Function
Within the body
parameter of the Scaffold
, we call the buildUI
function which returns a SafeArea
widget. This function aims to protect our content from any operating system interface intrusions, such as the notch or the status bar.
Defining the buildUI Function
Returning a SafeArea Widget
This widget ensures that our UI layout respects the safe areas of different devices maintaining a more uniform look.
Adding a Padding Widget
We nest a Padding
widget inside the SafeArea
for consistent spacing within our form.
Adding a Form Widget
Within the Padding
widget, we add a Form
widget which helps in grouping the form fields and managing their state.
child: Form(
key: _formKey,
child: Column(
children: [
// Form fields will be added here
],
),
)
Managing Form State
Creating a GlobalKey
Defining a FormKey Variable
We need a GlobalKey
to manage the state of our form. Inside your _HomePageState
, define a form key:
final _formKey = GlobalKey<FormState>();
Initializing the FormKey
Initialize the form key and link it with the Form
widget as shown above.
Linking the Form with the FormKey
By setting the key
property of the Form
widget to _formKey
, we can manage the form’s state throughout its lifecycle.
Adding Form Fields
Creating a Reusable Widget
To simplify our code and avoid redundancy, we create a reusable form field widget.
Creating a utils/widgets Folder
Create a new directory structure lib/utils/widgets
to hold our custom widgets.
Creating a CustomFormField Widget
Inside lib/utils/widgets
, create a new Dart file named custom_form_field.dart
and define the CustomFormField
stateless widget:
import 'package:flutter/material.dart';
class CustomFormField extends StatelessWidget {
final bool obscureText;
final String hintText;
final FormFieldValidator<String> validator;
final FormFieldSetter<String> onSaved;
CustomFormField({
this.obscureText = false,
@required this.hintText,
@required this.validator,
@required this.onSaved,
});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: TextFormField(
decoration: InputDecoration(
hintText: hintText,
),
obscureText: obscureText,
validator: validator,
onSaved: onSaved,
),
);
}
}
Using the CustomFormField Widget
Adding CustomFormField as a Child to the Column
Return to homepage.dart
and add instances of CustomFormField
within the column inside the Form
widget:
child: Column(
children: [
CustomFormField(
hintText: 'Email',
validator: (value) {
if (value.isEmpty || !value.isValidEmail) {
return 'Please enter a valid email';
}
return null;
},
onSaved: (value) {
_email = value;
},
),
CustomFormField(
hintText: 'Password',
obscureText: true,
validator: (value) {
if (value.isEmpty || value.length < 8) {
return 'Password must be at least 8 characters';
}
return null;
},
onSaved: (value) {
_password = value;
},
),
CustomFormField(
hintText: 'Phone',
validator: (value) {
if (value.isEmpty || !value.isValidPhone) {
return 'Please enter a valid phone number';
}
return null;
},
onSaved: (value) {
_phone = value;
},
),
ElevatedButton(
onPressed: _validateAndSave,
child: Text('Register'),
),
],
)
Customizing the CustomFormField Widget
Adding Padding
Padding is already added around each TextFormField
for spacing.
Using a TextFormField
The TextFormField
is configured to use validators and form state management mechanisms.
Adding an obscureText Parameter
This parameter ensures secure text entry, suitable for password fields.
Adding a hintText Parameter
The hintText
parameter provides contextual information about what data each field expects.
Updating the HomePage to Use the Parameters
Each form field now has custom validation logic and hint text to guide users.
Form Validation
Adding a Register Button
Creating an ElevatedButton
Add a button that users can press to submit the form.
Defining the onPressed Callback
Calling the validate() Method on the Form
Define the validation logic to ensure the form fields meet specified criteria:
void _validateAndSave() {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
// Handle successful form submission
}
}
Defining Validation Logic
Creating an extensions Folder
Create a directory lib/utils/extensions
.
Creating a StringExtensions File
Inside extensions
, create a file named string_extensions.dart
:
extension StringExtensions on String {
bool get isValidEmail {
final RegExp emailRegex = RegExp(r'^[^@]+@[^@]+\.[^@]+');
return emailRegex.hasMatch(this);
}
bool get isValidPassword {
return this.length >= 8;
}
bool get isValidPhone {
final RegExp phoneRegex = RegExp(r'^[0-9]{10}$');
return phoneRegex.hasMatch(this);
}
}
Using Regular Expressions
Regular expressions are used to match specific string patterns for validation.
Adding a Validator Parameter to CustomFormField
The validator
parameter has already been added to our CustomFormField
.
Implementing Validators for Each Field in HomePage
The validation for each field is implemented using the StringExtensions
.
Saving Form Data
Creating Variables to Store Form Data
Within _HomePageState
, define variables to store the form data:
String _email, _password, _phone;
Adding an onSaved Parameter to CustomFormField
The onSaved
parameter has been added to handle saving input data.
Implementing onSaved Callbacks
Saving Email Data
Save the email data to _email
:
onSaved: (value) {
_email = value;
}
Saving Password Data
Save the password data to _password
:
onSaved: (value) {
_password = value;
}
Saving Phone Data
Save the phone data to _phone
:
onSaved: (value) {
_phone = value;
}
Calling the save() Method on the Form
Invoke the save method in _validateAndSave
:
_formKey.currentState.save();
Printing the Saved Data
Print the saved data to the console for debugging:
print('Email: $_email, Password: $_password, Phone: $_phone');
Additional Features
Resetting the Form
Occasionally, you may want to provide a means to reset the form fields.
Using the reset() Method on the FormKey
Add a reset button to the UI:
ElevatedButton(
onPressed: () {
_formKey.currentState.reset();
},
child: Text('Reset'),
),
Get Source Code for free:
Conclusion
Managing form in Flutter can be achieved efficiently with the Form
widget. This comprehensive guide has walked you through setting up a form, managing its state, validating inputs, and saving form data. By creating reusable form field widgets and leveraging extensions for validation, we’ve built a robust registration page that ensures data integrity. By mastering these techniques, you can significantly improve form handling in your Flutter applications.
Happy Coding…!
Leave a Reply