gpt4 book ai didi

Flutter 自定义 FormField : validate and save methods are not called

转载 作者:IT王子 更新时间:2023-10-29 06:58:17 27 4
gpt4 key购买 nike

我是 Flutter 的新手,我在创建自定义表单域方面遇到了一些困难。问题是我的自定义 FormField 中的验证器和 onSaved 方法都没有被调用。我真的不知道为什么当我触发 formKey.currentState.validate()formKey.currentState.save() 时它们会被忽略。

目前这是一个非常简单的小部件,带有输入文本和按钮。该按钮将获取用户的当前位置,并使用当前地址更新文本字段。当用户在文本字段中输入地址时,它将在焦点丢失时获取该地址的位置(我还与 Google map 集成,但我对其进行了简化以隔离问题)。

这是我的表单字段的构造函数:

class LocationFormField extends FormField<LocationData> {

LocationFormField(
{FormFieldSetter<LocationData> onSaved,
FormFieldValidator<LocationData> validator,
LocationData initialValue,
bool autovalidate = false})
: super(
onSaved: onSaved,
validator: validator,
initialValue: initialValue,
autovalidate: autovalidate,
builder: (FormFieldState<LocationData> state) {
return state.build(state.context);
});

@override
FormFieldState<LocationData> createState() {
return _LocationFormFieldState();
}
}

因为我需要在我的自定义 FormField 中处理状态,所以我在 FormFieldState 对象中构建它。按下按钮时更新位置状态:

class _LocationFormFieldState extends FormFieldState<LocationData> {

@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
TextField(
focusNode: _addressInputFocusNode,
controller: _addressInputController,
decoration: InputDecoration(labelText: 'Address'),
),
SizedBox(height: 10.0),
FlatButton(
color: Colors.deepPurpleAccent,
textColor: Colors.white,
child: Text('Locate me !'),
onPressed: _updateLocation,
),
],
);
}

void _updateLocation() async {
print('current value: ${this.value}');
final double latitude = 45.632;
final double longitude = 17.457;
final String formattedAddress = await _getAddress(latitude, longitude);
print(formattedAddress);

if (formattedAddress != null) {
final LocationData locationData = LocationData(
address: formattedAddress,
latitude: latitude,
longitude: longitude);

_addressInputController.text = locationData.address;

// save data in form
this.didChange(locationData);
print('New location: ' + locationData.toString());
print('current value: ${this.value}');
}
}

这就是我在我的应用程序中实例化它的方式。这里没什么特别的;我把它放在一个带有表单键的表单中。还有另一个 TextFormField 来验证这个是否正常工作:

ma​​in.dart

Widget _buildLocationField() {
return LocationFormField(
initialValue: null,
validator: (LocationData value) {
print('validator location');
if (value.address == null || value.address.isEmpty) {
return 'No valid location found';
}
},
onSaved: (LocationData value) {
print('location saved: $value');
_formData['location'] = value;
},
); // LocationFormField
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: Container(
margin: EdgeInsets.all(10.0),
child: Form(
key: _formKey,
child: SingleChildScrollView(
padding: EdgeInsets.symmetric(horizontal: targetPadding / 2),
child: Column(
children: <Widget>[
_buildTitleTextField(),
SizedBox(
height: 10.0,
),
_buildLocationField(),
SizedBox(
height: 10.0,
),
_buildSubmitButton(),
],
),
),
),
),
),
);
}

由表单提交按钮触发的提交方法将尝试验证然后保存表单。

只打印保存在表单中的数据:

void _submitForm() {
print('formdata : $_formData');

if (!_formKey.currentState.validate()) {
return;
}
_formKey.currentState.save();

print('formdata : $_formData');
}

但是 _formData['location'] 总是返回 null,并且永远不会调用验证器(日志中不会打印“验证器位置”或“保存的位置”)。

我创建了一个示例存储库来重现此问题。您可以尝试运行该项目,首先单击 Locate me !按钮,然后是 https://github.com/manumura/flutter-location-form-field 处的保存按钮

最佳答案

答案一:把Builder的build方法放在

替换 FormField 的构建器

builder: (FormFieldState<LocationData> state) {
return state.build(state.context);
});

使用自定义构建器函数

builder: (FormFieldState<LocationData> state) {
return Column(
children: <Widget>[
TextField(
focusNode: _addressInputFocusNode,
controller: _addressInputController,
decoration: InputDecoration(labelText: 'Address'),
),
SizedBox(height: 10.0),
FlatButton(
color: Colors.deepPurpleAccent,
textColor: Colors.white,
child: Text('Locate me !'),
onPressed: _updateLocation,
),
],
});

答案二:伪CustomFormFieldState

您不能扩展 FormFieldState,因为重写“构建”函数会导致错误(在下面解释)

但是,您可以创建一个将 FormFieldState 作为参数的 Widget,使其成为一个单独的类,就像它扩展 FormFieldState 一样(对我来说,这比上述方法更清晰)

class CustomFormField extends FormField<List<String>> {
CustomFormField({
List<String> initialValue,
FormFieldSetter<List<String>> onSaved,
FormFieldValidator<List<String>> validator,
}) : super(
autovalidate: false,
onSaved: onSaved,
validator: validator,
initialValue: initialValue ?? List(),
builder: (state) {
return CustomFormFieldState(state);
});

}

class CustomFormFieldState extends StatelessWidget {
FormFieldState<List<String>> state;
CustomFormFieldState(this.state);

@override
Widget build(BuildContext context) {
return Container(), //The Widget(s) to build your form field
}
}

解释

扩展 FormFieldState 不起作用的原因是因为覆盖 FormFieldState 对象中的构建方法导致 FormFieldState 未注册到表单本身。

下面是我为了得到解释而遵循的函数列表

1) 您的 _LocationFormFieldState 覆盖了构建方法,这意味着 FormFieldState 的构建方法永远不会执行

@override
Widget build(BuildContext context)

2) FormFieldState 的构建方法将自身注册到当前的FormState

///function in FormFieldState    
Widget build(BuildContext context) {
// Only autovalidate if the widget is also enabled
if (widget.autovalidate && widget.enabled)
_validate();
Form.of(context)?._register(this);
return widget.builder(this);
}

3) FormState 然后将FormFieldState 保存在一个List 中

  void _register(FormFieldState<dynamic> field) {
_fields.add(field);
}

4) 然后,当 FormState 保存/验证时,它循环遍历 FormFieldStates 列表

/// Saves every [FormField] that is a descendant of this [Form].
void save() {
for (FormFieldState<dynamic> field in _fields)
field.save();
}

通过覆盖构建方法,您会导致 FormField 未注册到表单,这就是保存和加载表单不会调用自定义 FormField 的方法的原因。

如果 FormState._register() 方法是公共(public)的而不是私有(private)的,您可以在 _LocationFormFieldState.build 方法中调用此方法以将您的应用程序注册到表单,但很遗憾,因为它是一个私有(private)函数,您不能。

另请注意,如果您要在 CustomFormFieldState 的构建方法中调用 super.build() 函数,它会导致 StackOverflow

  @override
Widget build(BuildContext context) {
super.build(context); //leads to StackOverflow!
return _buildFormField(); //anything you want
}

关于Flutter 自定义 FormField : validate and save methods are not called,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54848639/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com