主题
表单
Form
Form
继承自 StatefulWidget
对象,它对应的状态类为 FormState
dart
Form({
required Widget child,
bool autovalidate = false,
WillPopCallback onWillPop,
VoidCallback onChanged,
})
autovalidate
:是否自动校验输入内容;当为true
时,每一个子 FormField 内容发生变化时都会自动校验合法性,并直接显示错误信息。否则,需要通过调用FormState.validate()
来手动校验onWillPop
:决定Form
所在的路由是否可以直接返回(如点击返回按钮),该回调返回一个Future
对象,如果 Future 的最终结果是false
,则当前路由不会返回;如果为true
,则会返回到上一个路由。此属性通常用于拦截返回按钮onChanged
:Form
的任意一个子FormField
内容发生变化时会触发此回调
FormField
Form
的子孙元素必须是FormField
类型
dart
const FormField({
...
FormFieldSetter<T> onSaved, //保存回调
FormFieldValidator<T> validator, //验证回调
T initialValue, //初始值
bool autovalidate = false, //是否自动校验。
})
为了方便使用,Flutter 提供了一个TextFormField
组件,它继承自FormField
类
FormState
FormState
为Form
的State
类,可以通过Form.of()
或GlobalKey
获得。我们可以通过它来对Form
的子孙FormField
进行统一操作
FormState.validate()
:调用此方法后,会调用Form
子孙FormField的validate
回调,如果有一个校验失败,则返回false,所有校验失败项都会返回用户返回的错误提示。FormState.save()
:调用此方法后,会调用Form
子孙FormField
的save
回调,用于保存表单内容FormState.reset()
:调用此方法后,会将子孙FormField
的内容清空。
登录例子
dart
class _HomePageState extends State<HomePage> {
TextEditingController _usernameController = TextEditingController();
TextEditingController _passwordController = TextEditingController();
GlobalKey _formKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Home')),
body: Padding(
padding: const EdgeInsets.all(18.0),
child: Form(
key: _formKey, // 设置globalKey,用于后面获取FormState
autovalidateMode: AutovalidateMode.onUserInteraction,
child: Column(
children: [
TextFormField(
autofocus: true,
controller: _usernameController,
decoration: InputDecoration(labelText: "用户名"),
validator: (v) => v!.trim().length > 0 ? null : "用户名不能为空",
),
TextFormField(
controller: _passwordController,
decoration: InputDecoration(labelText: "密码"),
obscureText: true,
validator: (v) => v!.trim().length > 5 ? null : "密码不能少于 6 位",
),
Container(
alignment: Alignment.center,
child: ElevatedButton(
onPressed: () {
if ((_formKey.currentState as FormState).validate()) {
// 验证通过提交数据
}
},
child: Text('登录')
)
)
],
),
)
)
);
}
}
登录按钮的
onPressed
方法中不能通过Form.of(context)
来获取原因是,此处的
context
为FormPage
的context,而Form.of(context)
是根据所指定context
向根去查找,而FormState
是在FormPage
的子树中,所以不行。正确的做法是通过Builder
来构建登录按钮,Builder
会将widget
节点的context
作为回调参数dartContainer( alignment: Alignment.center, child: Builder(builder: (context) { return ElevatedButton( onPressed: () { if (Form.of(context)?.validate() ?? false) { // 验证通过提交数据 } }, child: Text('登录') ); }) )