flutter_fast_forms 18.0.0 flutter_fast_forms: ^18.0.0 copied to clipboard
Flutter Fast Forms is the only Dart package you need to build Flutter forms fast.
Flutter Fast Forms #
Flutter Fast Forms is the only Dart package you need to build Flutter forms fast.
It adds these missing features to the Flutter SDK:
FastFormControl<T>
convenience widgets that wrap Material / Cupertino form controls in aFormField<T>
according to the already built-inTextFormField
/DropdownButtonFormField
FastForm
widget that wraps the built-inForm
widget for providing the current form field values inonChanged
callbackFastFormArray
widget that aggregates a flexible number of homogeneous controls in a singleFormField<T>
FastChipsInput
widget that converts text input into chips as defined by Material Design- Conditional form fields
touched
validation state- Common
FormFieldValidator<T>
functions
Table of Contents #
Getting Started #
1. Add a FastForm
to your widget tree:
class MyFormPage extends StatelessWidget {
MyFormPage({Key? key, required this.title}) : super(key: key);
final formKey = GlobalKey<FormState>();
final String title;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: SafeArea(
child: SingleChildScrollView(
child: FastForm(
formKey: formKey,
children: [],
),
),
),
);
}
}
2. Add FastFormControl<T>
children to the FastForm
:
FastForm(
formKey: formKey,
children: [
const FastTextField(
name: 'field_destination',
labelText: 'Destination',
placeholder: 'Where are you going?',
),
FastDateRangePicker(
name: 'field_check_in_out',
labelText: 'Check-in - Check-out',
firstDate: DateTime.now(),
lastDate: DateTime.now().add(const Duration(days: 365)),
),
const FastCheckbox(
name: 'field_travel_purpose',
labelText: 'Travel purpose',
titleText: 'I am travelling for work',
),
],
),
3. Wrap the children in a FastFormSection
for visual grouping and consistent padding:
FastForm(
formKey: formKey,
children: [
FastFormSection(
header: const Text('My Form'),
padding: EdgeInsets.all(16.0),
children: [
const FastTextField(
name: 'field_destination',
labelText: 'Destination',
placeholder: 'Where are you going?',
),
// ...
],
),
]
),
Widget Catalog #
FastFormControl<T> |
field value type | wraps Material widget | wraps Cupertino widget when adaptive: true |
---|---|---|---|
FastAutocomplete<O> |
String |
Autocomplete<O> |
no |
FastCheckbox |
bool |
CheckboxListTile |
CupertinoCheckbox |
FastChoiceChips<T> |
Set<T> |
ChoiceChip |
no |
FastCalendar |
DateTime |
CalendarDatePicker |
no |
FastChipsInput |
List<String> |
RawAutocomplete<String> + InputChip |
no |
FastDatePicker |
DateTime |
showDatePicker |
CupertinoDatePicker |
FastDateRangePicker |
DateTimeRange |
showDateRangePicker |
no |
FastDropdown<T> |
T |
DropdownButtonFormField<T> |
no |
FastRadioGroup<T> |
T |
RadioListTile<T> |
no |
FastRangeSlider |
RangeValues |
RangeSlider |
no |
FastSegmentedButton<T> |
Set<T> |
SegmentedButton<T> |
no |
FastSegmentedControl<T> |
T extends Object |
no | CupertinoSlidingSegmentedControl<T> |
FastSlider |
double |
Slider.adaptive |
CupertinoSlider |
FastSwitch |
bool |
SwitchListTile |
CupertinoSwitch |
FastTextField |
String |
TextFormField |
CupertinoTextFormFieldRow |
FastTimePicker |
TimeOfDay |
showTimePicker |
no use FastDatePicker with CupertinoDatePickerMode.time |
Adaptive Form Fields #
While some form controls are unique to a certain platform, various others are present in multiple design languages.
By default, Flutter Fast Forms uses Material widgets on any platform.
This behavior is adjustable so that platform-specific Cupertino widgets are automatically rendered on iOS.
Tip
The widget catalog tells you which FastFormControl
is adaptive.
📓 Example: Always use Cupertino widgets on iOS in a FastForm
.
FastForm(
formKey: formKey,
adaptive: true,
children: [
const FastSwitch(
name: 'switch',
titleText: 'Disable text field',
),
FastTextField(
name: 'text_field',
labelText: 'Just some sample text field',
),
]
),
Note
- When
adaptive
is set totrue
any built-inFormFieldBuilder
returns a corresponding Cupertino widget on iOS, if it exists.
📓 Example: Only use the Cupertino widget on iOS for a dedicated FastSwitch
.
FastForm(
formKey: formKey,
children: [
const FastSwitch(
name: 'switch',
adaptive: true,
titleText: 'Disable text field',
),
]
),
Conditional Form Fields #
Not all controls in a form are autonomous and act independent of each other.
Occasionally, the state of a form field might be directly related to the state of some other form field as well.
Flutter Fast Forms allows you to define such conditions declaratively.
📓 Example: A FastTextField
that is disabled when a FastSwitch
is selected.
1. Add the conditions
property to the conditional form field and assign an empty Map
:
const FastSwitch(
name: 'switch',
titleText: 'Disable text field',
),
FastTextField(
name: 'text_field',
labelText: 'Just some sample text field',
conditions: {},
),
2. Choose a suitable FastConditionHandler
as Map
key and assign a FastConditionList
:
const FastSwitch(
name: 'switch',
titleText: 'Disable text field when selected',
),
FastTextField(
name: 'text_field',
labelText: 'Just some sample text field',
conditions: {
FastCondition.disabled: FastConditionList([]),
},
)
Note
A FastConditionHandler
is a function that runs whenever a FastConditionList
is checked and determines what happens when the condition is either met or not.
3. Add a FastCondition
relating the field to another field:
const FastSwitch(
name: 'switch',
titleText: 'Disable text field when selected',
),
FastTextField(
name: 'text_field',
labelText: 'Just some sample text field',
conditions: {
FastCondition.disabled: FastConditionList([
FastCondition(
target: 'switch',
test: (value, field) => value is bool && value,
),
]),
},
),
Note
target
is the name
of the FastFormField
that the form field depends on.
📓 Example: A FastTextField
that is enabled when a FastSwitch
or a FastCheckbox
is selected.
const FastCheckbox(
name: 'checkbox',
titleText: 'Enable text field when selected',
),
const FastSwitch(
name: 'switch',
titleText: 'Enable text field when selected',
),
FastTextField(
name: 'text_field',
enabled: false,
labelText: 'Just some sample text field',
conditions: {
FastCondition.enabled: FastConditionList([
FastCondition(
target: 'switch',
test: (value, field) => value is bool && value,
),
FastCondition(
target: 'checkbox',
test: (value, field) => value is bool && value,
),
]),
},
),
📓 Example: A FastTextField
that is disabled when both a FastSwitch
and a FastCheckbox
are selected.
const FastCheckbox(
name: 'checkbox',
titleText: 'Disable text field when selected',
),
const FastSwitch(
name: 'switch',
titleText: 'Disable text field when selected',
),
FastTextField(
name: 'text_field',
labelText: 'Just some sample text field',
conditions: {
FastCondition.enabled: FastConditionList(
[
FastCondition(
target: 'switch',
test: (value, field) => value is bool && value,
),
FastCondition(
target: 'checkbox',
test: (value, field) => value is bool && value,
),
],
match: FastConditionMatch.every,
),
},
),
Note
match
specifies how all individual test results in the list are evaluated to determine whether the condition is met.
Custom Form Fields #
There are use cases where the widget catalog does not fully satisfy your individual requirements.
As a consequence you have to add non-standard controls to your form.
With Flutter Fast Forms you're free to wrap any custom widget into a form field.
📓 Example: A simple widget that provides a random integer whenever a button is pressed.
1. Create a stateful widget class extending FastFormField<T>
with a corresponding FastFormFieldState<T>
:
class MyCustomField extends FastFormField<int> {
const MyCustomField({
super.builder = myCustomFormFieldBuilder,
super.key,
required super.name,
});
@override
MyCustomFieldState createState() => MyCustomFieldState();
}
class MyCustomFieldState extends FastFormFieldState<int> {
@override
MyCustomField get widget => super.widget as MyCustomField;
}
Note
builder
andname
are required constructor parameters ofFastFormField
.builder
is a standard FlutterFormFieldBuilder<T>
.
2. Implement the FormFieldBuilder<T>
returning your custom widget:
Widget myCustomFormFieldBuilder(FormFieldState<int> field) {
field as MyCustomFieldState;
final MyCustomFieldState(:decoration, :didChange, :value) = field;
return InputDecorator(
decoration: decoration,
child: Row(
children: [
ElevatedButton(
child: const Text('Create random number'),
onPressed: () => didChange(Random().nextInt(1 << 32)),
),
if (value is int)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: Text(value.toString()),
)
],
),
);
}
Note
- Casting
field
is mandatory to accessFastFormField
properties and functions. - Always call
field.didChange()
to update the value of the form field.
3. Add all super-initializer parameters that the form field should support:
class MyCustomField extends FastFormField<int> {
const MyCustomField({
super.builder = myCustomFormFieldBuilder,
super.decoration,
super.enabled,
super.helperText,
super.initialValue,
super.key,
super.labelText,
required super.name,
super.onChanged,
super.onReset,
super.onSaved,
super.onTouched,
super.validator,
});
@override
MyCustomFieldState createState() => MyCustomFieldState();
}
Note
Always make sure that you apply certain super-initializer parameters like decoration
or enabled
in your builder functions.
Otherwise assigning those arguments when invoking the constructor won't have any effect.