上一篇文章介绍了各式各样的文本展示,用到了TextField组件。TextField比较简单,使用起来比较方便,但是并不支持表单数据的前置验证和错误提示。今天要给大家介绍的组件是表单组件Form、FormField。
6.1 Form
Form作为一个容器,可包裹多个表单字段(FormField)。FormField是一个抽象类,TextFormField是FormField的一个实现类,因此可以在Form中使用TextFormField。
6.1.1 Form构造方法
//
/// * [GlobalKey], a key that is unique across the entire app.
/// * [FormField], a single form field widget that maintains the current state.
/// * [TextFormField], a convenience widget that wraps a [TextField] widget in a [FormField].
const Form({
Key key,
@required this.child,
this.autovalidate = false,
this.onWillPop,
this.onChanged,
})
6.1.2 Form属性说明
属性 | 作用 |
---|---|
Widget child | 孩子节点 |
bool autovalidate | 是否自动验证,如果为true,表单字段将在每次更改后立即验证和更新其错误文本;如果为false,则需要调用FormState.validate进行验证。 |
WillPopCallback onWillPop | 决定Form所在的路由是否可以直接返回(如点击返回按钮),该回调返回一个Future对象,如果Future的最终结果是false,则当前路由不会返回;如果为true,则会返回到上一个路由。此属性通常用于拦截返回按钮 |
VoidCallback onChanged | Form的任意一个子FormField内容发生变化时会触发此回调 |
6.2 TextFormField
TextFormField 基于 TextField 封装了一层,能够做到数据的前置校验。TextFormField继承自FormField。
6.2.1 TextFormField构造方法
TextFormField({
Key key,
this.controller,
String initialValue,
FocusNode focusNode,
InputDecoration decoration = const InputDecoration(),
TextInputType keyboardType,
TextCapitalization textCapitalization = TextCapitalization.none,
TextInputAction textInputAction,
TextStyle style,
StrutStyle strutStyle,
TextDirection textDirection,
TextAlign textAlign = TextAlign.start,
bool autofocus = false,
bool readOnly = false,
bool showCursor,
bool obscureText = false,
bool autocorrect = true,
bool autovalidate = false,
bool maxLengthEnforced = true,
int maxLines = 1,
int minLines,
bool expands = false,
int maxLength,
VoidCallback onEditingComplete,
ValueChanged<String> onFieldSubmitted,
FormFieldSetter<String> onSaved,
FormFieldValidator<String> validator,
List<TextInputFormatter> inputFormatters,
bool enabled = true,
double cursorWidth = 2.0,
Radius cursorRadius,
Color cursorColor,
Brightness keyboardAppearance,
EdgeInsets scrollPadding = const EdgeInsets.all(20.0),
bool enableInteractiveSelection = true,
InputCounterWidgetBuilder buildCounter,
})
从TextFormField的构造函数中可以看出,builder返回了一个TextField,所以对于TextFormField的属性参考TextField即可;由于TextFormField继承自FormField,所以FormField的属性TextFormField也可以使用。
6.2.2 TextFormField属性
属性 | 作用 |
---|---|
FormFieldSetter onSaved | 保存回调,调用FormState.save的回调 |
FormFieldValidator validator | 验证回调,如果开启autovalidate: true,那么将会自动检验输入的值,如果没有则会在表单提交的时候检验(FormState.validate),该函数只允许返回验证失败的错误信息以及验证通过时返回null。 |
T initialValue | 初始值 |
bool autovalidate | 是否自动校验 |
bool enabled | 是否可用 |
6.3 FormState
FormState为Form的State类,可以通过Form.of()或GlobalKey获得。
这个 Form 我们可以通过指定 key 来统一整个 Form 中的输入框,参照 Form 的构造函数说明可以发现:
/// final _formKey = GlobalKey<FormState>();
一般通过创建一个 GolbalKey 关联
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
- FormState.validate():调用此方法后,会调用FormField的validate回调,如果有一个校验失败,则返回false,所有校验失败项都会返回用户返回的错误提示。
- FormState.save():调用此方法后,会调用FormField的save回调,用于保存表单内容
- FormState.reset():调用此方法后,会将FormField的内容清空,清空不会清空初始值。
6.4 代码实例
1 校验电话号码
2 校验用户名不为空
3 可以清空
import 'package:flutter/material.dart';
class FormFieldWidget extends StatefulWidget {
FormFieldWidget({Key key}) : super(key: key);
@override
_FormFieldWidgetState createState() => _FormFieldWidgetState();
}
class _FormFieldWidgetState extends State<FormFieldWidget> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("FormWidget")),
body: Padding(
padding: EdgeInsets.all(10),
child: Column(
children: <Widget>[
Form(
key: _formKey,
onChanged: () {
print('change');
},
child: Column(
children: <Widget>[
TextFormField(
decoration: InputDecoration(
hintText: '电话号码',
),
validator: (value) {
RegExp reg = new RegExp(r'^\d{11}$');
if (!reg.hasMatch(value)) {
return '请输入11位手机号码';
}
return null;
},
),
TextFormField(
decoration: InputDecoration(
hintText: '用户名',
),
validator: (value) {
if (value.isEmpty) {
return '请输入用户名';
}
return null;
},
),
],
),
),
SizedBox(height: 10),
Row(children: <Widget>[
Expanded(
child: RaisedButton(
onPressed: () {
_formKey.currentState.reset();
},
child: Text('清空'),
),
)
]),
SizedBox(height: 10),
Row(
children: <Widget>[
Expanded(
child: RaisedButton(
child: Text('提交'),
onPressed: () {
if (_formKey.currentState.validate()) {
Scaffold.of(context).showSnackBar(SnackBar(
content: Text('提交成功'),
));
}
},
),
)
],
),
],
),
),
);
}
}