Flutter 颤振:当字段在ListView中不可见时,未调用TextFormField验证程序
我也遇到过同样的问题,我按照提供的建议解决了这个问题(我在Flutter 颤振:当字段在ListView中不可见时,未调用TextFormField验证程序,flutter,dart,Flutter,Dart,我也遇到过同样的问题,我按照提供的建议解决了这个问题(我在onChanged中调用setState())。。。问题是,在我的例子中,如果字段在视图中不可见(如果滚动视图直到不再显示),则不会调用validator函数,因此我可以在无效状态下提交表单 如何触发当前未显示在列表视图中的字段的验证 更新: 以下是该问题的简单演示(我正在一个独立的简单应用程序中使用它进行调试): 导入“包装:颤振/材料.省道”; void main()=>runApp(MyApp()); 类MyForm扩展了State
onChanged
中调用setState()
)。。。问题是,在我的例子中,如果字段在视图中不可见(如果滚动视图直到不再显示),则不会调用validator
函数,因此我可以在无效状态下提交表单
如何触发当前未显示在列表视图中的字段的验证
更新:
以下是该问题的简单演示(我正在一个独立的简单应用程序中使用它进行调试):
导入“包装:颤振/材料.省道”;
void main()=>runApp(MyApp());
类MyForm扩展了StatefulWidget{
@凌驾
状态createState(){
返回_MyFormState();
}
}
类_MyFormState扩展了状态{
静态最终全局键_formKey=GlobalKey();
最终地图模型=地图();
@凌驾
void initState(){
打印('initState()');
对于(int i=0;i<20;i++){
模型[i]=null;
}
super.initState();
}
字符串验证(字符串值){
返回值.isEmpty?不能为空!:null;
}
void submitForm(){
final FormState FormState=\u formKey.currentState;
if(formState.validate()){
打印(“表格有效”);
formState.save();
}否则{
打印('表格无效');
}
}
@凌驾
小部件构建(构建上下文){
列表字段=[];
对于(int i=0;i<20;i++){
Widget Widget=TextFormField(
初始值:模型[i],
装饰:输入装饰(
labelText:“字段$i”,
),
验证程序:验证,
onFieldSubmitted:(字符串值){
打印('field$i onFieldSubmitted()');
设置状态(){
模型[i]=数值;
});
},
onChanged:(字符串值){
打印('field$i onChanged()');
设置状态(){
模型[i]=数值;
});
},
onSaved:(字符串值){
打印('field$i onSaved()');
设置状态(){
模型[i]=数值;
});
},
);
添加(小部件);
}
字段。添加(RaisedButton(
子项:文本('save'),
onPressed:submitForm,
));
报税表(
键:_formKey,
子:ListView(
孩子们:田野,
),
);
}
}
类MyApp扩展了无状态小部件{
@凌驾
小部件构建(构建上下文){
返回材料PP(
标题:“颤振演示”,
主题:主题数据(
主样本:颜色。蓝色,
),
家:脚手架(
appBar:appBar(
标题:文本(“形式测试”),
),
正文:MyForm(),
),
);
}
}
我可以想出两种方法
1) 你不能使用验证器。使用提供者提供的验证方法。如果提供程序发回一个错误,则显示一个snackbar。
2) 您可以使用验证器。您还必须在提供程序中使用验证方法。如果提供程序返回错误,请使用scrollcontroller滚动到所需的列表元素,并希望表单字段验证器在该时间被激活。解决方案很简单,只是不要使用列表视图
,而是依赖SingleChildScrollView
(并将表单本身作为子表单传递)
导入“包装:颤振/材料.省道”;
void main()=>runApp(MyApp());
类MyForm扩展了StatefulWidget{
@凌驾
状态createState(){
返回_MyFormState();
}
}
类_MyFormState扩展了状态{
静态最终全局键_formKey=GlobalKey();
最终地图模型=地图();
@凌驾
void initState(){
打印('initState()');
对于(int i=0;i<20;i++){
模型[i]=null;
}
super.initState();
}
字符串验证(字符串值){
返回值.isEmpty?不能为空!:null;
}
void submitForm(){
final FormState FormState=\u formKey.currentState;
if(formState.validate()){
打印(“表格有效”);
formState.save();
}否则{
打印('表格无效');
}
}
@凌驾
小部件构建(构建上下文){
列表字段=[];
对于(int i=0;i<20;i++){
Widget Widget=TextFormField(
初始值:模型[i],
装饰:输入装饰(
labelText:“字段$i”,
),
验证程序:验证,
onFieldSubmitted:(字符串值){
打印('field$i onFieldSubmitted()');
设置状态(){
模型[i]=数值;
});
},
);
添加(小部件);
}
字段。添加(RaisedButton(
子项:文本('save'),
onPressed:submitForm,
));
返回SingleChildScrollView(
孩子:表格(
键:_formKey,
子:列(
孩子们:田野,
),
),
);
}
}
类MyApp扩展了无状态小部件{
@凌驾
小部件构建(构建上下文){
返回材料PP(
标题:“颤振演示”,
主题:主题数据(
主样本:颜色。蓝色,
),
家:脚手架(
appBar:appBar(
标题:文本(“形式测试”),
),
正文:MyForm(),
),
);
}
}
您所说的“提供者”是什么意思?这个->?如果您不想使用提供程序。。您可以在widget类中的单独方法中编写验证逻辑。问题不在验证逻辑中,如果字段在视图中可见,则所有字段验证程序都可以正常工作。。。关键是,如果字段不可见,FormState
的validate()
在调用validate()后,不会调用隐藏字段的验证器(换句话说,这就像是针对表单的一部分而不是完整字段进行验证)。如果字段滚动到视图中,是否会显示错误?是,正如我所写的,只要字段当前显示在视图中,验证工作正常
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyForm extends StatefulWidget {
@override
State createState() {
return _MyFormState();
}
}
class _MyFormState extends State<MyForm> {
static final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final Map<int, String> model = Map<int, String>();
@override
void initState() {
print('initState()');
for (int i = 0; i < 20; i++) {
model[i] = null;
}
super.initState();
}
String validate(String value) {
return value.isEmpty ? 'Cannot be blank!' : null;
}
void submitForm() {
final FormState formState = _formKey.currentState;
if (formState.validate()) {
print('form is valid');
formState.save();
} else {
print('form is invalid');
}
}
@override
Widget build(BuildContext context) {
List<Widget> fields = [];
for (int i = 0; i < 20; i++) {
Widget widget = TextFormField(
initialValue: model[i],
decoration: InputDecoration(
labelText: 'field $i',
),
validator: validate,
onFieldSubmitted: (String value) {
print('field $i onFieldSubmitted()');
setState(() {
model[i] = value;
});
},
onChanged: (String value) {
print('field $i onChanged()');
setState(() {
model[i] = value;
});
},
onSaved: (String value) {
print('field $i onSaved()');
setState(() {
model[i] = value;
});
},
);
fields.add(widget);
}
fields.add(RaisedButton(
child: Text('save'),
onPressed: submitForm,
));
return Form(
key: _formKey,
child: ListView(
children: fields,
),
);
}
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: Text('form test'),
),
body: MyForm(),
),
);
}
}
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyForm extends StatefulWidget {
@override
State createState() {
return _MyFormState();
}
}
class _MyFormState extends State<MyForm> {
static final GlobalKey<FormState> _formKey = GlobalKey();
final Map<int, String> model = Map<int, String>();
@override
void initState() {
print('initState()');
for (int i = 0; i < 20; i++) {
model[i] = null;
}
super.initState();
}
String validate(String value) {
return value.isEmpty ? 'Cannot be blank!' : null;
}
void submitForm() {
final FormState formState = _formKey.currentState;
if (formState.validate()) {
print('form is valid');
formState.save();
} else {
print('form is invalid');
}
}
@override
Widget build(BuildContext context) {
List<Widget> fields = [];
for (int i = 0; i < 20; i++) {
Widget widget = TextFormField(
initialValue: model[i],
decoration: InputDecoration(
labelText: 'field $i',
),
validator: validate,
onFieldSubmitted: (String value) {
print('field $i onFieldSubmitted()');
setState(() {
model[i] = value;
});
},
);
fields.add(widget);
}
fields.add(RaisedButton(
child: Text('save'),
onPressed: submitForm,
));
return SingleChildScrollView(
child: Form(
key: _formKey,
child: Column(
children: fields,
),
),
);
}
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: Text('form test'),
),
body: MyForm(),
),
);
}
}