Flutter PageView内多个表单通过单个onPressed触发统一校验咨询
问题根因
- 多个
Form组件共用同一个GlobalKey<FormState>,后渲染的Form会覆盖之前Key的绑定关系,导致仅最后一个表单的校验生效 - 第一页表单绑定的
formKey[0]未提前定义,会触发运行时异常 - 部分
TextFormField的validator方法仅调用了校验逻辑未返回结果,校验错误不会触发提示 - PageView默认会销毁不可见页面的状态,切走的表单校验时会出现
currentState为null的情况,校验无效
解决方案
步骤1:声明独立的表单Key
替换State中原来的单个FormKey定义,为每个带表单的页面分配独立Key:
// 3个带表单的页面对应3个独立的FormKey final List<GlobalKey<FormState>> _formKeys = List.generate(3, (_) => GlobalKey<FormState>()); bool? policy; int currentPage = 0;
步骤2:绑定表单Key
给每个页的Form绑定对应索引的Key:
- 第一页(用户信息页)Form key填
_formKeys[0] - 第二页(手机号/CPF页)Form key填
_formKeys[1] - 第四页(密码页)Form key填
_formKeys[2]
步骤3:保活PageView页面状态
给PageView的每个子页面外层套AutomaticKeepAlive,防止页面切走后状态丢失:
PageView( controller: controller.pageViewController, onPageChanged: (index) { currentPage = index; }, children: [ // 每个页面都套一层保活组件 AutomaticKeepAlive( wantKeepAlive: true, child: SafeArea( // 原来的页面内容不变 ), ), // 剩余3个页面都做同样的保活处理 ... ] )
步骤4:修复validator返回逻辑
所有输入框的validator必须返回校验结果,比如密码页的校验逻辑修改为:
// 密码输入框校验 validator: (value) { return InputValidators().passwordValidator(value!); }, // 确认密码输入框校验 validator: (value) { if (value != controller.passwordCreate.text) { return "As senhas não coincidem"; } else { return InputValidators().passwordValidator(value!); } },
步骤5:修改提交校验逻辑
点击按钮时先全量校验所有表单+隐私政策状态,校验通过再提交:
onpressed: () { if (currentPage == 3) { // 全量校验所有表单 bool allFormValid = true; for (var formKey in _formKeys) { if (!(formKey.currentState?.validate() ?? false)) { allFormValid = false; break; } } // 校验隐私政策是否勾选 if (allFormValid && policy == true) { // 校验全部通过,提交数据 final user = User( cpf: controller.cpfCreate.value.text, name: controller.nameCreate.value.text, email: controller.emailCreate.value.text, password: controller.passwordCreate.value.text, telephone: controller.telefoneCreate.value.text, policyAccepted: policy!, ); print(user); // 后续跳转逻辑 } else { if (policy != true) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text("请先同意隐私政策")), ); } } } else { // 非最后一页,校验当前页内容通过后再跳转 bool canGoNext = true; if (currentPage == 0 || currentPage == 1) { // 校验当前页表单 canGoNext = _formKeys[currentPage].currentState?.validate() ?? false; } else if (currentPage == 2) { // 校验隐私政策是否勾选 canGoNext = policy == true; if (!canGoNext) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text("请先同意隐私政策才能继续")), ); } } if (canGoNext) { controller.pageViewController.nextPage( duration: const Duration(milliseconds: 400), curve: Curves.easeInOut, ); } } }
内容的提问来源于stack exchange,提问作者Ronaldo
相关产品推荐
相关产品推荐

