主题
表单
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('登录') ); }) )
