带有嵌套自定义FormField的Flutter Form onSaved执行顺序

时间:2019-10-29 12:07:34

标签: flutter dart

我有一个自定义的FormField 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树高多少倍?

谢谢。

1 个答案:

答案 0 :(得分:1)

答案很晚,但是我认为这是因为MyFancyTextFormField扩展了FormField并在生成器中返回了另外的TextFormField。如果将MyFancyTextFormField变成返回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);
  }
}