首页 > 解决方案 > 带有嵌套自定义 FormFields 的 Flutter Form onSaved 执行顺序

问题描述

我有一个自定义的FormField<String>MyFancyTextFormField ,它只是用一些额外的包装了一个 TextFormField 。

我想单独使用这个 FormField,但我也想在另一个 FormField 中使用它:TextList,它基本上是一个填充了 MyFancyTextFormFields 的列。

我想出了这个:

class FirstWidget extends StatefulWidget {
  @override
  State createState() => FirstWidgetState();
}

class FirstWidgetState extends State<FirstWidget> {
  GlobalKey<FormState> _form = GlobalKey<FormState>();
  List<String> initial = ['one', 'two', 'three'];
  List<String> modified;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: <Widget>[
          Form(
            key: _form,
            child: TextList(initialValue: initial, onSaved: (values) => print('TextList saved with: ${modified = values}')),
          ),
          RaisedButton(
            child: Text('Save'),
            onPressed: () {
              _form.currentState.save();
              print('Initial value was: $initial, modified value is: $modified');
            },
          )
        ],
      ),
    );
  }
}

class TextList extends FormField<List<String>> {
  TextList({List<String> initialValue, FormFieldSetter<List<String>> onSaved})
      : super(
            initialValue: initialValue,
            onSaved: onSaved,
            builder: (state) {
              //Make a copy
              List<String> _value = List.of(state.value);
              //This just creates the list of MyFancyTextFormField
              List<Widget> fields = _value
                  .asMap()
                  .map<int, Widget>((i, val) => MapEntry(
                      i,
                      MyFancyTextFormField(
                          initialValue: _value[i],
                          onSaved: (val) {
                            print('MyFancyTextFormField[$i] saved with $val');
                            state.didChange(_value..replaceRange(i, i + 1, [val]));
                          })))
                  .values
                  .toList();
              return Column(
                children: fields,
              );
            });
}

class MyFancyTextFormField extends FormField<String> {
  MyFancyTextFormField({
    String initialValue,
    FormFieldSetter<String> onSaved,
  }) : super(
            initialValue: initialValue,
            onSaved: (value) => onSaved(value),
            builder: (state) => TextFormField(
                  initialValue: initialValue,
                  onSaved: onSaved,
                ));
}

问题在于,当我保存()表单状态时,框架将首先保存我的顶级 FormField TextList,然后再保存我的叶级 FormField MyFancyTextFormField。

这是我的输出:

I/flutter (  615): TextList saved with: [one, two, three]
I/flutter (  615): MyFancyTextFormField[0] saved with one
I/flutter (  615): MyFancyTextFormField[0] saved with oneee
I/flutter (  615): MyFancyTextFormField[1] saved with two
I/flutter (  615): MyFancyTextFormField[1] saved with two
I/flutter (  615): MyFancyTextFormField[2] saved with three
I/flutter (  615): MyFancyTextFormField[2] saved with threeeeeeeeee
I/flutter (  615): Initial value was: [one, two, three], modified value is: [one, two, three]

由于第一次执行 save() 后,我的 TextList 的状态已正确更新,如果我再次运行 save(),我将得到预期的输出:

I/flutter (  615): TextList saved with: [oneee, two, threeeeeeeeee]
I/flutter (  615): MyFancyTextFormField[0] saved with one
I/flutter (  615): MyFancyTextFormField[0] saved with oneee
I/flutter (  615): MyFancyTextFormField[1] saved with two
I/flutter (  615): MyFancyTextFormField[1] saved with two
I/flutter (  615): MyFancyTextFormField[2] saved with three
I/flutter (  615): MyFancyTextFormField[2] saved with threeeeeeeeee
I/flutter (  615): Initial value was: [one, two, three], modified value is: [oneee, two, threeeeeeeeee]

为什么 MyFancyTextFormField(s) 的 onSaved 被调用了两次?

有没有办法让我的预期结果比调用 state.save() 的次数比我的 FormField 的树高更好?

先感谢您。

标签: flutterdart

解决方案


很晚的答案,但我认为这是因为在构建器中MyFancyTextFormField扩展FormField并返回了一个TextFormField附加值。如果你MyFancyTextFormField变成一个返回 a 的无状态小部件,TextFormField你会得到你想要的:

class MyFancyTextFormField extends StatelessWidget {
  final String initialValue;
  final FormFieldSetter<String> onSaved; 

   MyFancyTextFormField({
    this.initialValue,
    this.onSaved,  
  }) ;

  @override
  Widget build(BuildContext context) {
    return TextFormField(
        initialValue: initialValue,
        onSaved: this.onSaved);
  }
}

推荐阅读