我们可以在验证后从 Flutter 表单中获取错误字段列表吗?这将帮助开发人员使用焦点节点将注意力重定向到错误的字段。
问问题
1175 次
2 回答
4
扩展 Guillaume 的答案,我将功能包装到一个可重用的类中。
您可以在此处查看 DartPad 上的工作示例:https ://www.dartpad.dev/61c4ccddbf29a343c971ee75e60d1038
import 'package:flutter/material.dart';
class FormValidationManager {
final _fieldStates = Map<String, FormFieldValidationState>();
FocusNode getFocusNodeForField(key) {
_ensureExists(key);
return _fieldStates[key].focusNode;
}
FormFieldValidator<T> wrapValidator<T>(String key, FormFieldValidator<T> validator) {
_ensureExists(key);
return (input) {
final result = validator(input);
_fieldStates[key].hasError = (result?.isNotEmpty ?? false);
return result;
};
}
List<FormFieldValidationState> get erroredFields =>
_fieldStates.entries.where((s) => s.value.hasError).map((s) => s.value).toList();
void _ensureExists(String key) {
_fieldStates[key] ??= FormFieldValidationState(key: key);
}
void dispose() {
_fieldStates.entries.forEach((s) {
s.value.focusNode.dispose();
});
}
}
class FormFieldValidationState {
final String key;
bool hasError;
FocusNode focusNode;
FormFieldValidationState({@required this.key})
: hasError = false,
focusNode = FocusNode();
}
要使用它,请像往常一样创建表单,但将 a 添加FormValidationManager
到您的状态类,然后使用该实例来包装您的验证方法。
用法:
class _MyWidgetState extends State<MyWidget> {
final _formKey = GlobalKey<FormState>();
final _formValidationManager = FormValidationManager();
@override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Column(
children: [
TextFormField(
focusNode: _formValidationManager.getFocusNodeForField('field1'),
validator: _formValidationManager.wrapValidator('field1', (value) {
if (value.isEmpty) {
return 'Please enter a value';
}
return null;
})),
TextFormField(
focusNode: _formValidationManager.getFocusNodeForField('field2'),
validator: _formValidationManager.wrapValidator('field2', (value) {
if (value.isEmpty) {
return 'Please enter a value';
}
return null;
})),
ElevatedButton(
onPressed: () {
if (!_formKey.currentState.validate()) {
_formValidationManager.erroredFields.first.focusNode.requestFocus();
}
},
child: Text('SUBMIT'))
],
),
);
}
@override
void dispose() {
_formValidationManager.dispose();
super.dispose();
}
}
于 2021-07-22T23:52:43.850 回答
4
我认为不可能从Form
对象或FormState
.
但这里有一种方法可以获得你想要的结果(关注错误的字段):
class _MyWidgetState extends State<MyWidget> {
FocusNode _fieldToFocus;
List<FocusNode> _focusNodes;
final _formKey = GlobalKey<FormState>();
final _numberOfFields = 3;
String _emptyFieldValidator(String val, FocusNode focusNode) {
if (val.isEmpty) {
_fieldToFocus ??= focusNode;
return 'This field cannot be empty';
}
return null;
}
@override
void initState() {
super.initState();
_focusNodes =
List<FocusNode>.generate(_numberOfFields, (index) => FocusNode());
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(actions: [
IconButton(
icon: Icon(Icons.check),
onPressed: () {
if (_formKey.currentState.validate()) {
print('Valid form');
} else {
_fieldToFocus?.requestFocus();
_fieldToFocus = null;
}
},
),
]),
body: Form(
key: _formKey,
child: Column(children: [
...List<TextFormField>.generate(
_numberOfFields,
(index) => TextFormField(
decoration: InputDecoration(hintText: "Field $index"),
focusNode: _focusNodes[index],
validator: (val) => _emptyFieldValidator(val, _focusNodes[index]),
),
),
]),
),
);
}
}
您只需要FocusNode
为每个字段创建一个,因此您可以调用requestFocus
一个精确的字段(在您的情况下,该字段被认为是无效的)。然后在validator
表单字段的属性中,因为它是由 调用的方法,所以FormState.validate()
您需要设置一个临时变量,该变量将包含正确的FocusNode
。在我的示例中,我只设置_fieldToFocus
尚未使用??=
运算符分配的变量。在请求将焦点放在我设置的节点上之后_fieldToFocus
,null
它仍然可以用于另一个验证。
您可以尝试我在DartPad上使用的完整测试代码。
抱歉,如果我从您的问题中得到了一些启发,但我仍然希望这会对您有所帮助。
于 2020-09-10T18:54:01.460 回答