Form介绍
实际业务中,在正式向服务器提交数据前,都会对各个输入框数据进行合法性校验,但是对每一个
TextField
都分别进行校验将会是一件很麻烦的事。还有,如果用户想清除一组TextField
的内容,除了一个一个清除有没有什么更好的办法呢?为此,Flutter提供了一个Form
组件,它可以对输入框进行分组,然后进行一些统一操作,如输入内容校验、输入框重置以及输入内容保存。
Form
继承自StatefulWidget
对象,它对应的状态类为FormState
autovalidate
:是否自动校验输入内容;当为true
时,每一个子FormField内容发生变化时都会自动校验合法性,并直接显示错误信息。否则,需要通过调用FormState.validate()
来手动校验。onWillPop
:决定Form
所在的路由是否可以直接返回(如点击返回按钮),该回调返回一个Future
对象,如果Future的最终结果是false
,则当前路由不会返回;如果为true
,则会返回到上一个路由。此属性通常用于拦截返回按钮。onChanged
:Form
的任意一个子FormField
内容发生变化时会触发此回调。FormField
Form
的子孙元素必须是FormField
类型,FormField
是一个抽象类,定义几个属性,FormState
内部通过它们来完成操作,FormField
部分定义如下:const FormField({ ... FormFieldSetter<T> onSaved, //保存回调 FormFieldValidator<T> validator, //验证回调 T initialValue, //初始值 bool autovalidate = false, //是否自动校验。 })
为了方便使用,Flutter提供了一个
TextFormField
组件,它继承自FormField
类,也是TextField
的一个包装类,所以除了FormField
定义的属性之外,它还包括TextField
的属性。FormState
FormState
为Form
的State
类,可以通过Form.of()
或GlobalKey
获得。我们可以通过它来对Form
的子孙FormField
进行统一操作。我们看看其常用的三个方法:
FormState.validate()
:调用此方法后,会调用Form
子孙FormField的validate
回调,如果有一个校验失败,则返回false,所有校验失败项都会返回用户返回的错误提示。FormState.save()
:调用此方法后,会调用Form
子孙FormField
的save
回调,用于保存表单内容FormState.reset()
:调用此方法后,会将子孙FormField
的内容清空。
demo
登录页面,输入账号,密码,然后点击登录按钮判断账号是否存在,密码是否正确
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; void main() { runApp(FormApp()); } class FormApp extends StatefulWidget { @override State<StatefulWidget> createState() { return FormTest(); } } class FormTest extends State { TextEditingController _phoneController = new TextEditingController(); TextEditingController _passController = new TextEditingController(); GlobalKey _formKey = new GlobalKey<FormState>(); @override Widget build(BuildContext context) { // TODO: implement build return MaterialApp( home: Scaffold( appBar: AppBar( backgroundColor: Colors.red, title: Text( 'Form表单练习', style: TextStyle(fontSize: 18, color: Colors.yellow), ), ), body: Column( children: <Widget>[ Container( margin: EdgeInsets.all(30), child: Form( key: _formKey, //设置globalKey,用于后面获取FormState child: Column( children: <Widget>[ TextFormField( autovalidate: true, //开启自动校验 validator: (v) { return v.trim().length > 0 ? null : '手机号不能为空'; }, keyboardType: TextInputType.phone, controller: _phoneController, decoration: InputDecoration( icon: Icon(Icons.phone), filled: true, fillColor: Colors.yellow, hintText: "手机号", border: OutlineInputBorder( borderRadius: BorderRadius.circular(20), borderSide: BorderSide(color: Colors.blue, width: 1)), )), SizedBox(height: 10), TextFormField( validator: (v) { return v.trim().length > 5 ? null : '密码不能少于6位'; }, controller: _passController, keyboardType: TextInputType.visiblePassword, obscureText: true, decoration: InputDecoration( icon: Icon(Icons.lock), filled: true, fillColor: Colors.yellow, border: OutlineInputBorder( borderRadius: BorderRadius.circular(20), borderSide: BorderSide(color: Colors.blue, width: 1)), )), SizedBox(height: 10), Row( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ FlatButton( onPressed: () { (_formKey.currentState as FormState).reset(); //获取数据 this.setState(() {}); }, color: Colors.blue, child: Text( '重置', style: TextStyle(color: Colors.white, fontSize: 18), ), ), SizedBox( width: 30, ), FlatButton( onPressed: () { if ((_formKey.currentState as FormState) .validate()) { //验证通过提交数据 } //获取数据 this.setState(() {}); }, color: Colors.blue, child: Text( '登录', style: TextStyle(color: Colors.white, fontSize: 18), ), ) ], ), SizedBox( height: 20, ), Text( '账号是:${_phoneController.text}\n密码是:${_passController.text}', style: TextStyle( fontSize: 20, color: Colors.blue, fontWeight: FontWeight.w700), ) ], ), ), ), ], ), ), ); } }
运行效果
这里我有一个疑问,期待解决,就是当我正确输入之后,点击登录,然后再点击重置 ,是没有办法清空的,如果有大神看到这个问题,还请赐教,万分感谢~