Flutter FormBuilder – flutter_form_builder
该包通过消除构建表单、验证字段、响应更改以及收集最终用户输入所需的样板代码,帮助创建 Flutter 中的数据收集表单。
其中还包括 FormBuilder 的常见现成表单输入字段。这为您提供了一种便捷的方式来添加常见的现成输入字段,而不是从头开始创建自己的 FormBuilderField。
示例
import 'package:flutter_form_builder/flutter_form_builder.dart';
...
final _formKey = GlobalKey<FormBuilderState>();
...
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
FormBuilder(
key: _formKey,
autovalidate: true,
child: Column(
children: <Widget>[
FormBuilderFilterChip(
name: 'filter_chip',
decoration: InputDecoration(
labelText: 'Select many options',
),
options: [
FormBuilderFieldOption(
value: 'Test', child: Text('Test')),
FormBuilderFieldOption(
value: 'Test 1', child: Text('Test 1')),
FormBuilderFieldOption(
value: 'Test 2', child: Text('Test 2')),
FormBuilderFieldOption(
value: 'Test 3', child: Text('Test 3')),
FormBuilderFieldOption(
value: 'Test 4', child: Text('Test 4')),
],
),
FormBuilderChoiceChip(
name: 'choice_chip',
decoration: InputDecoration(
labelText: 'Select an option',
),
options: [
FormBuilderFieldOption(
value: 'Test', child: Text('Test')),
FormBuilderFieldOption(
value: 'Test 1', child: Text('Test 1')),
FormBuilderFieldOption(
value: 'Test 2', child: Text('Test 2')),
FormBuilderFieldOption(
value: 'Test 3', child: Text('Test 3')),
FormBuilderFieldOption(
value: 'Test 4', child: Text('Test 4')),
],
),
FormBuilderDateTimePicker(
name: 'date',
// onChanged: _onChanged,
inputType: InputType.time,
decoration: InputDecoration(
labelText: 'Appointment Time',
),
initialTime: TimeOfDay(hour: 8, minute: 0),
// initialValue: DateTime.now(),
// enabled: true,
),
FormBuilderDateRangePicker(
name: 'date_range',
firstDate: DateTime(1970),
lastDate: DateTime(2030),
format: DateFormat('yyyy-MM-dd'),
onChanged: _onChanged,
decoration: InputDecoration(
labelText: 'Date Range',
helperText: 'Helper text',
hintText: 'Hint text',
),
),
FormBuilderSlider(
name: 'slider',
validator: FormBuilderValidators.compose([
FormBuilderValidators.min(context, 6),
]),
onChanged: _onChanged,
min: 0.0,
max: 10.0,
initialValue: 7.0,
divisions: 20,
activeColor: Colors.red,
inactiveColor: Colors.pink[100],
decoration: InputDecoration(
labelText: 'Number of things',
),
),
FormBuilderCheckbox(
name: 'accept_terms',
initialValue: false,
onChanged: _onChanged,
title: RichText(
text: TextSpan(
children: [
TextSpan(
text: 'I have read and agree to the ',
style: TextStyle(color: Colors.black),
),
TextSpan(
text: 'Terms and Conditions',
style: TextStyle(color: Colors.blue),
),
],
),
),
validator: FormBuilderValidators.equal(
context,
true,
errorText:
'You must accept terms and conditions to continue',
),
),
FormBuilderTextField(
name: 'age',
decoration: InputDecoration(
labelText:
'This value is passed along to the [Text.maxLines] attribute of the [Text] widget used to display the hint text.',
),
onChanged: _onChanged,
// valueTransformer: (text) => num.tryParse(text),
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(context),
FormBuilderValidators.numeric(context),
FormBuilderValidators.max(context, 70),
]),
keyboardType: TextInputType.number,
),
FormBuilderDropdown(
name: 'gender',
decoration: InputDecoration(
labelText: 'Gender',
),
// initialValue: 'Male',
allowClear: true,
hint: Text('Select Gender'),
validator: FormBuilderValidators.compose(
[FormBuilderValidators.required(context)]),
items: genderOptions
.map((gender) => DropdownMenuItem(
value: gender,
child: Text('$gender'),
))
.toList(),
),
],
),
),
Row(
children: <Widget>[
Expanded(
child: MaterialButton(
color: Theme.of(context).colorScheme.secondary,
child: Text(
"Submit",
style: TextStyle(color: Colors.white),
),
onPressed: () {
_formKey.currentState.save();
if (_formKey.currentState.validate()) {
print(_formKey.currentState.value);
} else {
print("validation failed");
}
},
),
),
SizedBox(width: 20),
Expanded(
child: MaterialButton(
color: Theme.of(context).colorScheme.secondary,
child: Text(
"Reset",
style: TextStyle(color: Colors.white),
),
onPressed: () {
_formKey.currentState.reset();
},
),
),
],
)
],
);
}
输入控件
当前支持的字段包括
FormBuilderCheckbox– 单个复选框字段FormBuilderCheckboxGroup– 用于多选的复选框列表FormBuilderChoiceChip– 创建一个充当单选按钮的芯片。FormBuilderDateRangePicker– 用于选择日期范围FormBuilderDateTimePicker– 用于 `Date`、`Time` 和 `DateTime` 输入FormBuilderDropdown– 用于从列表下拉中选择一个值FormBuilderFilterChip– 创建一个充当复选框的芯片。FormBuilderRadioGroup– 用于从单选控件列表中选择一个值FormBuilderRangeSlider– 用于从一系列值中选择一个范围FormBuilderSegmentedControl– 用于使用 `CupertinoSegmentedControl` 控件作为输入来选择一个值FormBuilderSlider– 用于在滑块上选择一个数值FormBuilderSwitch– 开/关切换字段FormBuilderTextField– Material Design 文本框输入。
为了创建表单中的输入字段,以及标签和任何适用的验证,所有类型的输入都支持几个属性,即
| 属性 | 类型 | 默认值 | 必需 | 描述 |
|---|---|---|---|---|
名称 |
字符串 |
是 |
这将形成表单值 Map 中的键 | |
initialValue |
T |
空 |
否 |
输入字段的初始值 |
enabled |
布尔值 |
真 |
否 |
确定字段控件是否接受用户输入。 |
装饰 |
InputDecoration |
InputDecoration() |
否 |
定义用于装饰字段的边框、标签、图标和样式。 |
validator |
FormFieldValidator<T> |
空 |
否 |
一个 `FormFieldValidator`,它将检查 `FormField` 中值的有效性 |
onChanged |
ValueChanged<T> |
空 |
否 |
当字段值更改时,此事件函数将立即触发 |
valueTransformer |
ValueTransformer<T> |
空 |
否 |
在保存到表单值之前转换字段值的功能。例如,将数字字段的 TextField 值从 `String` 转换为 `num` |
| 其余属性将由使用的控件类型决定。 |
构建自己的自定义字段
要在 `FormBuilder` 中构建自己的字段,我们使用 `FormBuilderField`,它要求您定义自己的字段。
var options = ["Option 1", "Option 2", "Option 3"];
FormBuilderField(
name: "name",
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(context),
]),
builder: (FormFieldState<dynamic> field) {
return InputDecorator(
decoration: InputDecoration(
labelText: "Select option",
contentPadding:
EdgeInsets.only(top: 10.0, bottom: 0.0),
border: InputBorder.none,
errorText: field.errorText,
),
child: Container(
height: 200,
child: CupertinoPicker(
itemExtent: 30,
children: options.map((c) => Text(c)).toList(),
onSelectedItemChanged: (index) {
field.didChange(options[index]);
},
),
),
);
},
),
以编程方式更改字段值
您可以一次更改一个字段的值,如下所示
_formKey.currentState.fields['color_picker'].didChange(Colors.black);
或者一次更改多个字段的值,如下所示
_formKey.currentState.patchValue({
'age': '50',
'slider': 6.7,
'filter_chip': ['Test 1'],
'choice_chip': 'Test 2',
'rate': 4,
'chips_test': [
Contact('Andrew', '[email protected]', 'https://d2gg9evh47fn9z.cloudfront.net/800px_COLOURBOX4057996.jpg'),
],
});
以编程方式触发错误
选项 1 – 使用 FormBuilder / FieldBuilderField 键
final _formKey = GlobalKey<FormBuilderState>();
final _emailFieldKey = GlobalKey<FormBuilderFieldState>();
...
FormBuilder(
key: _formKey,
child: Column(
children: [
FormBuilderTextField(
key: _emailFieldKey
name: 'email',
decoration: InputDecoration(labelText: 'Email'),
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(context),
FormBuilderValidators.email(context),
]),
),
RaisedButton(
child: Text('Submit'),
onPressed: () async {
if(await checkIfEmailExists()){
// Either invalidate using Form Key
_formKey.currentState?.invalidateField(name: 'email', errorText: 'Email already taken.');
// OR invalidate using Field Key
_emailFieldKey.currentState?.invalidate('Email already taken.');
}
},
),
],
),
),
选项 2 – 使用 InputDecoration.errorText
声明一个变量来存储您的错误
String _emailError;
在 `InputDecoration` 中使用该变量作为 `errorText`
FormBuilderTextField(
name: 'email',
decoration: InputDecoration(
labelText: 'Email',
errorText: _emailError,
),
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(context),
FormBuilderValidators.email(context),
]),
),
设置错误文本
RaisedButton(
child: Text('Submit'),
onPressed: () async {
setState(() => _emailError = null);
if(await checkIfEmailExists()){
setState(() => _emailError = 'Email already taken.');
}
},
),
条件验证
您还可以根据另一个字段的值来验证一个字段
FormBuilderRadioGroup(
decoration: InputDecoration(labelText: 'My best language'),
name: 'my_language',
validator: FormBuilderValidators.required(context),
options: [
'Dart',
'Kotlin',
'Java',
'Swift',
'Objective-C',
'Other'
]
.map((lang) => FormBuilderFieldOption(value: lang))
.toList(growable: false),
),
FormBuilderTextField(
name: 'specify',
decoration:
InputDecoration(labelText: 'If Other, please specify'),
validator: (val) {
if (_formKey.currentState.fields['my_language']?.value ==
'Other' &&
(val == null || val.isEmpty)) {
return 'Kindly specify your language';
}
return null;
},
),
生态系统
以下是可用于扩展 `flutter_form_builder` 功能的其他包。
- form_builder_validators – 提供了一种便捷的方式来验证输入到任何 Flutter `FormField` 的数据。
- form_builder_extra_fields – 提供与 `flutter_form_builder` 兼容的额外现成表单输入字段。
- form_builder_file_picker – 一个允许从用户设备存储中选择图像的 `FormbuilderField`。
- form_builder_image_picker – 一个允许从设备图库或相机中选择图像的 `FormbuilderField`。
- form_builder_map_field – 用于地理位置输入的 `FormbuilderField`。
- form_builder_phone_field – 用于国际电话号码输入的 `FormbuilderField`。
支持
问题与 PRs
以报告错误、回答问题或 PRs 的形式提供的任何支持都非常感谢。
咖啡?
如果这个包在您的项目交付中对您有所帮助,或者您只是想支持这个包,一杯咖啡将不胜感激?
