当前位置:网站首页>Flutter 从零开始 008 表单
Flutter 从零开始 008 表单
2022-06-30 10:46:00 【华为云】
表单Form
在实际业务开发中,在正式像服务器提交数据之前,都会对各个输入框数据进行合法性校验,但是对每一个TextField 都进行校验是一件很麻烦的事。如果用户想清除一组TextField 的数据,又非常的麻烦。flutter还给我们提供了一个From 组件,它可以对输入框进行分组,然后进行统一操作,如内容校验,输入框重置,输入内容保存等。
Form继承自StatefulWidget对象,它对应的状态类为FormState。我们先看看Form类的定义:
Form({ required Widget child, bool autovalidate = false, WillPopCallback onWillPop, VoidCallback onChanged,})
autovalidate : 是否自动校验输入内容,当为true 时,每个子FormFeild 内容发生变化时,都会自动校验合法性,并直接显示错误信息。否则,需要通过调用FormState.validate() 来手动校验。
onWillPop: 决定Form 所在的路由是否可以直接返回(如点击返回按钮),该回调返回一个Future对象,如果 Future 的最终结果是false,则当前路由不会返回;如果为true,则会返回到上一个路由。此属性通常用于拦截返回按钮。
onChanged:Form的任意一个子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为Form的State类,可以通过Form.of()或GlobalKey获得。我们可以通过它来对Form的子孙FormField进行统一操作。我们看看其常用的三个方法:
FormState.validate():调用此方法后,会调用Form子孙FormField的validate回调,如果有一个校验失败,则返回false,所有校验失败项都会返回用户返回的错误提示。
FormState.save():调用此方法后,会调用Form子孙FormField的save回调,用于保存表单内容
FormState.reset():调用此方法后,会将子孙FormField的内容清空。
示例
我们修改一下上面用户登录的示例,在提交之前校验:
用户名不能为空,如果为空则提示“用户名不能为空”。
密码不能小于 6 位,如果小于 6 为则提示“密码不能少于 6 位”。
class _MyHomePageState extends State<MyHomePage> { TextEditingController userController = TextEditingController(); TextEditingController passController = TextEditingController(); GlobalKey _globalKey = GlobalKey<FormState>(); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Form( key: _globalKey, //设置globalKey,用于后面获取FormState autovalidateMode: AutovalidateMode.onUserInteraction, child: Column( children: [ TextFormField( autofocus: true, controller: userController, decoration: InputDecoration( labelText: "用户名", hintText: "用户名或邮箱", icon: Icon(Icons.person), ), validator: (v) { return v!.trim().isNotEmpty ? null : '用户名不能为空'; }, ), SizedBox( height: 20, ), TextFormField( controller: passController, decoration: InputDecoration( labelText: "密码", hintText: "输入密码", icon: Icon(Icons.lock), ), obscureText: true, validator: (v) { return v!.trim().length > 5 ? null : '密码不能少于6位'; }, ), Padding( padding: EdgeInsets.only(top: 20), child: Expanded( child: ElevatedButton( child: Padding( padding: EdgeInsets.all(16), child: Text("登录"), ), onPressed: () { // 通过_formKey.currentState 获取FormState后, // 调用validate()方法校验用户名密码是否合法,校验 // 通过后再提交数据。 if((_globalKey.currentState as FormState).validate()){ print("验证通过,开始提交"); } }, ), ), ), ], ), ), ); }}
运行效果如下
注意,登录按钮的onPressed方法中不能通过Form.of(context)来获取,原因是,此处的context为FormTestRoute的context,而Form.of(context)是根据所指定context向根去查找,而FormState是在FormTestRoute的子树中,所以不行。正确的做法是通过Builder来构建登录按钮,Builder会将widget节点的context作为回调参数:
Expanded( // 通过Builder来获取ElevatedButton所在widget树的真正context(Element) child:Builder(builder: (context){ return ElevatedButton( ... onPressed: () { //由于本widget也是Form的子代widget,所以可以通过下面方式获取FormState if(Form.of(context).validate()){ //验证通过提交数据 } }, ); }))
下一节我们将介绍指示器
边栏推荐
- Double-DQN笔记
- Go zero micro Service Practice Series (VIII. How to handle tens of thousands of order requests per second)
- Pytorch notes torch nn. BatchNorm1d
- MySQL export SQL script file
- Every time I look at my colleagues' interface documents, I get confused and have a lot of problems...
- LVGL 8.2 Simple Image button
- 100 important knowledge points that SQL must master: using table aliases
- promise async和await的方法与使用
- 数据库什么时候需要使用索引【杭州多测师】【杭州多测师_王sir】
- Qt之实现动效导航栏
猜你喜欢
The jetpack compose dropdownmenu is displayed following the finger click position
考研这些“不靠谱”的经验有多害人?
China will force a unified charging interface. If Apple does not bow its head, iPhone will be kicked out of the Chinese market
深潜Kotlin协程(十六):Channel
Handler-源码分析
LVGL 8.2 Image
What is erdma as illustrated by Coptic cartoon?
高通发布物联网案例集 “魔镜”、数字农业已经成为现实
深潜Kotlin协程(十八):冷热数据流
中移OneOS开发板学习入门
随机推荐
Cp2112 teaching example of using USB to IIC communication
创建型-配置工厂
压缩状态DP位运算
DQN笔记
Deep dive kotlin Xie Cheng (17): Actor
SQL必需掌握的100个重要知识点:使用表别名
单片机 MCU 固件打包脚本软件
基于HAL库的LED驱动库
微信表情符号被写入判决书,你发的每个 emoji 都可能成为呈堂证供
ARouter 最新问题合集
博弈论入门
LVGL 8.2 Image styling and offset
14岁懂社会-《关于“工作的幸福”这件事儿》读书笔记
在 sCrypt 中实现高效的椭圆曲线点加法和乘法
[untitled]
Rejuvenated Dell and apple hit each other, and the two old PC enterprises declined rapidly
CP2112使用USB转IIC通信教学示例
pytorch 筆記 torch.nn.BatchNorm1d
【西安交通大学】考研初试复试资料分享
【STL源码剖析】容器(待补充)