基础组件:表单

news/2024/9/19 17:04:55/文章来源:https://www.cnblogs.com/linuxAndMcu/p/18375951

实际业务中,在正式向服务器提交数据前,都会对各个输入框数据进行合法性校验,但是对每一个TextField都分别进行校验将会是一件很麻烦的事。还有,如果用户想清除一组TextField的内容,除了一个一个清除有没有什么更好的办法呢?为此,Flutter提供了一个Form 组件,它可以对输入框进行分组,然后进行一些统一操作,如输入内容校验、输入框重置以及输入内容保存。

一、Form

Form继承自StatefulWidget对象,它对应的状态类为FormState。我们先看看Form类的定义:

Form({required Widget child,bool autovalidate = false,WillPopCallback onWillPop,VoidCallback onChanged,
})
  • autovalidate:是否自动校验输入内容;当为true时,每一个子 FormField 内容发生变化时都会自动校验合法性,并直接显示错误信息。否则,需要通过调用FormState.validate()来手动校验。
  • onWillPop:决定Form所在的路由是否可以直接返回(如点击返回按钮),该回调返回一个Future对象,如果 Future 的最终结果是false,则当前路由不会返回;如果为true,则会返回到上一个路由。此属性通常用于拦截返回按钮。
  • onChangedForm的任意一个子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

FormStateFormState类,可以通过Form.of()GlobalKey获得。我们可以通过它来对Form的子孙FormField进行统一操作。我们看看其常用的三个方法:

  • FormState.validate():调用此方法后,会调用Form子孙FormField的validate回调,如果有一个校验失败,则返回false,所有校验失败项都会返回用户返回的错误提示。
  • FormState.save():调用此方法后,会调用Form子孙FormFieldsave回调,用于保存表单内容
  • FormState.reset():调用此方法后,会将子孙FormField的内容清空。

四、示例

我们修改一下上面用户登录的示例,在提交之前校验:

  1. 用户名不能为空,如果为空则提示“用户名不能为空”。
  2. 密码不能少于 6 位,如果小于 6 为则提示“密码不能少于 6 位”。

完整代码:

import 'package:flutter/material.dart';class FormTestRoute extends StatefulWidget {@override_FormTestRouteState createState() => _FormTestRouteState();
}class _FormTestRouteState extends State<FormTestRoute> {TextEditingController _unameController = TextEditingController();TextEditingController _pwdController = TextEditingController();GlobalKey _formKey = GlobalKey<FormState>();@overrideWidget build(BuildContext context) {return Form(key: _formKey, //设置globalKey,用于后面获取FormStateautovalidateMode: AutovalidateMode.onUserInteraction,child: Column(children: <Widget>[TextFormField(autofocus: true,controller: _unameController,decoration: InputDecoration(labelText: "用户名",hintText: "用户名或邮箱",icon: Icon(Icons.person),),// 校验用户名validator: (v) {return v!.trim().isNotEmpty ? null : "用户名不能为空";},),TextFormField(controller: _pwdController,decoration: InputDecoration(labelText: "密码",hintText: "您的登录密码",icon: Icon(Icons.lock),),obscureText: true,//校验密码validator: (v) {return v!.trim().length > 5 ? null : "密码不能少于6位";},),// 登录按钮Padding(padding: const EdgeInsets.only(top: 28.0),child: Row(children: <Widget>[Expanded(child: ElevatedButton(child: Padding(padding: const EdgeInsets.all(16.0),child: Text("登录"),),onPressed: () {// 通过_formKey.currentState 获取FormState后,// 调用validate()方法校验用户名密码是否合法,校验// 通过后再提交数据。if ((_formKey.currentState as FormState).validate()) {//验证通过提交数据}},),),],),)],),);}
}

运行后效果如下图所示:

Flutter_edit_G.png

注意,登录按钮的onPressed方法中不能通过Form.of(context)来获取FormState,原因是,此处的contextFormTestRoute的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()){//验证通过提交数据}},);})
)

其实context正是操作Widget所对应的Element的一个接口,由于Widget树对应的Element都是不同的,所以context也都是不同的,有关context的更多内容会在本书后面进阶篇中详细讨论。Flutter中有很多“of(context)”这种方法,读者在使用时一定要注意context是否正确。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/786089.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ctfhub-rce-部分做题记录

命令注入 检查网页显示内容,可以直接看到源代码。大致意思是:检查用户输入的 GET 请求,判断用户是否输入了 ip 信息。如果输入了 ip 信息,则使用用户输入的这个 ip 数据执行一个 shell 命令 "ping -c 4" 。 输入 127.0.0.1;cat 104211044913917.php 没回显,查看…

linux 安装nginx

1.nginx 官网下载nginx 包 (选择稳定版) https://nginx.org/en/download.html 2.上传到linux服务器,解压 tar -zxvf nginx-1.26.2.tar.gz 3.cd到 nginx-1.26.2 , 执行 ./configure 4. 执行 make 5 .执行 make install 7.搜索 nginx 所安装的目录 , whereis …

Android Qcom USB Driver学习(八)

因为要看usb charging的问题,所以需要补充一下battery的相关知识,算是入门吧 BAT SCH(1)VBATT_VSNS_P (2)BAT_THERM (3)I2C_SDA (4)I2C_SCL (5)VBATT_VSNS_M sbl1_hw_pre_ddr_init: (1)pm_device_init (2)pm_driver_init (3) pm_sbl_chg_init (1) pm_device_init没有研究过,…

JuiceFS 在多云架构中加速大模型推理

在大模型的开发与应用中,数据预处理、模型开发、训练和推理构成四个关键环节。本文将重点探讨推理环节。在之前的博客中,社区用户 BentoML 和贝壳的案例提到了使用 JuiceFS 社区版来提高模型加载的效率。本文将结合我们的实际经验,详细介绍企业版在此场景下的优势。 下图是一…

基础组件:ICON

Flutter 中,可以像 Web 开发一样使用 iconfont,iconfont 即“字体图标”,它是将图标做成字体文件,然后通过指定不同的字符而显示不同的图片。在字体文件中,每一个字符都对应一个位码,而每一个位码对应一个显示字形,不同的字体就是指字形不同,即字符对应的字形是不同的。…

Docker部署Nginx,无法访问的解决办法

最近用阿里云的服务器部署了一下Nginx,发现无法通过外网访问,排除掉防火墙和端口映射的问题,最终在阿里云官方发现解决办法,docker0网桥的网段与内网eth0网段冲突,可能导致Nginx无法访问,修改Docker的网段后正常访问. 1.运行以下命令,查看docker0和eth0网段是否冲突 route …

一起单测引起的项目加载失败惨案

一、前言最近在开发一个功能模块时,在功能自测阶段,通过使用单测测试功能的完整性,在测试单测联通性使用到静态方法测试时,发现单测报错,通过查阅解决方案发现需要对Javaassist包进行排包或者升版本处理。通过排包解决掉单测报错,在部署项目时发现频繁报bean注入失败问题…

基础组件:图片

Flutter 中,我们可以通过Image组件来加载并显示图片,Image的数据源可以是asset、文件、内存以及网络。 ImageProvider ImageProvider 是一个抽象类,主要定义了图片数据获取的接口load(),从不同的数据源获取图片需要实现不同的ImageProvider ,如AssetImage是实现了从Asset中…

第6篇 好用免费的开发AI:FittenCode Chart,功能类似chatgpt

你所不知道的免费,又好用的AI,帮助你提高工作效率; 1.打开vs,点击扩展》管理工具,然后搜索Fitten Code,安装下载完成后,重新打开vs2.打开vs,管理工具,就会出现Fitten Code ,选择 open chat window,解决方案管理下就会出现Fittencode Chart,3.输入问题,就可以对话,…

SonarQube 安装及使用

简介 SonarQube是一款用于代码质量管理的开源工具,是静态代码检查工具,采用 B/S 架构它主要用于管理源代码的质量,可以支持众多计算机语言,比如 php,java, C#, go,C/C++, Cobol, JavaScrip, Groovy 等。sonar 可以通过 PMD,CheckStyle,Findbugs 等等代码规则检测工具来…

基础组件:按钮

Material 组件库中提供了多种按钮组件如ElevatedButton、TextButton、OutlinedButton等,它们都是直接或间接对RawMaterialButton组件的包装定制,所以他们大多数属性都和RawMaterialButton一样。在介绍各个按钮时我们先介绍其默认外观,而按钮的外观大都可以通过属性来自定义,…