Как заставить «Конструктор форм Flutter» распознавать отправленные данные формы из вопросов в предупреждении RFlutter?

#forms #flutter #popup #alert #flutter-form-builder

#формы #flutter #всплывающее окно #предупреждение #flutter-form-builder

Вопрос:

Я создаю форму, используя пакет «Конструктор форм Flutter» 4.0.2.

Большинство вопросов формы отображаются на экране, но последние два отображаются в последовательных * всплывающих окнах, созданных с помощью пакета предупреждений RFlutter 1.1.0

* Под «последовательным» я подразумеваю, что в нижней части главного экрана формы есть кнопка «Опубликовать» (см. Первое изображение сразу ниже). При нажатии появляется всплывающее окно с предупреждением RFlutter (см. 2-й снимок экрана ниже) с предпоследним вопросом FormBuilderRadioGroup («q11»). При нажатии кнопки «Далее» появляется еще одно всплывающее окно предупреждения RFlutter, в котором отображается последний вопрос FormBuilderRadioGroup («q12»). При нажатии кнопки «Завершить публикацию» отправляется вся форма конструктора форм Flutter.

скриншот главного экрана, перед появлением всплывающих окон с предупреждениями

скриншот всплывающего окна 1-го предупреждения

скриншот всплывающего окна 2-го предупреждения

Пользовательский интерфейс работает хорошо, но проблема в том, что ничего из вопросов во всплывающих окнах предупреждений (Q11 и Q12) не отправляется вместе с формой (см. Снимок консоли ниже — q1, q2 и q3 также имеют проблемы, но это не то, о чем я здесь спрашиваю).

скриншот консоли

Вот код (для длины пропущены нерелевантные части):

 // This is the stateful widget that the main application instantiates, per https://api.flutter.dev/flutter/widgets/Form-class.html
class SandboxWriteReviewScreen extends StatefulWidget {
  // BEGIN code from material_tag_editor
  final String title = 'Material Tag Editor Demo';
// END code from material_tag_editor

  @override
  _SandboxWriteReviewScreenState createState() =>
      _SandboxWriteReviewScreenState();
}

// This is the private State class that goes with WriteReviewScreen
class _SandboxWriteReviewScreenState extends State<SandboxWriteReviewScreen> {
  var data;
  AutovalidateMode autovalidateMode = AutovalidateMode.always;
  bool readOnly = false;
  bool showSegmentedControl = true;
  //final _newFormbuilderKey = GlobalKey<FormState>();
  final _newnewFormbuilderKey = GlobalKey<FormBuilderState>();

  // above "GlobalKey" lets us generate a unique, app-wide ID that we can associate with our form, per https://fluttercrashcourse.com/blog/realistic-forms-part1
  final ValueChanged _onChanged = (val) => print(val);

  // BEGIN  related to FormBuilderTextField in form below
  final _ageController = TextEditingController(text: '45');
  bool _ageHasError = false;
  // END related to FormBuilderTextField in form below

  String qEleven;
  String qTwelve;

  // BEGIN code from material_tag_editor
  List<String> qOne = [];
  final FocusNode _focusNode = FocusNode();

  onDelete(index) {
    setState(() {
      qOne.removeAt(index);
    });
  }

  // below = reiteration for cons

  List<String> qThree = [];
  //final FocusNode _focusNode = FocusNode();

  uponDelete(index) {
    // NOTE: "uponDelete" for cons vs. "onDelete" for pros
    setState(() {
      qThree.removeAt(index);
    });
  }

// END code from material_tag_editor

  //final _user = User();

  List<bool> isSelected;

  int starIconColor =
      0xffFFB900; // was 0xffFFB900;  0xffD49428 is from this image: https://images.liveauctioneers.com/houses/logos/lg/bartonsauction550_large.jpg?auto=webpamp;format=pjpgamp;width=140

  @override
  void initState() {
    //isSelected = [true, false];
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
 

Продолжение (пропущенная панель приложений):

 body: SingleChildScrollView(
        child: Container(
          child: Builder(
            builder: (context) => FormBuilder(
              // was "builder: (context) => Form("
              key: _newnewFormbuilderKey,
              initialValue: {
                'date': DateTime.now(),
              },
              child: Padding(
                padding: const EdgeInsets.all(14.0),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: <Widget>[
                    SizedBox(
                      height: 12.0,
                    ),
                    RichText(
                      text: TextSpan(
                        style: TextStyle(
                          color: Colors.blue,
                        ),
                        children: <TextSpan>[
                          TextSpan(
                            text:
                                'Q1 via TagEditor', // was 'What are 3 good or positive things about the house, property or neighborhood?', //  [ 1 ​]
                            style: TextStyle(
                              fontWeight: FontWeight.bold,
                              fontSize: 16.0,
                            ),
                          ),
                          TextSpan(
                            text: '  (optional)',
                            style: TextStyle(
                              fontWeight: FontWeight.normal,
                              fontStyle: FontStyle.italic,
                              fontSize: 14.0,
                              color: Colors.black54,
                            ), // was 'misleading or inaccurate?',
                          ),
                        ],
                      ),
                    ),
                    // BEGIN code from material_tag_editor
                    Padding(
                      padding: const EdgeInsets.only(top: 16.0),
                      child: TagEditor(
                        length: qOne.length,
                        delimiters: [
                          ','
                        ], // was delimiters: [',', ' '],  Also tried "return" ('u2386',) and 'u{2386}'
                        hasAddButton: true,
                        textInputAction: TextInputAction
                            .next, // moves user from one field to the next!!!!
                        autofocus: false,
                        maxLines: 1,

                        // focusedBorder: OutlineInputBorder(
                        //   borderSide: BorderSide(color: Colors.lightBlue),
                        //   borderRadius: BorderRadius.circular(20.0),
                        // ),
                        inputDecoration: const InputDecoration(
                          // below was "border: InputBorder.none,"
                          isDense: true,
                          border: OutlineInputBorder(
                            borderRadius: const BorderRadius.all(
                              const Radius.circular(20.0),
                            ),
                          ),
                          focusedBorder: OutlineInputBorder(
                            borderSide: BorderSide(color: Colors.lightBlue),
                            borderRadius: const BorderRadius.all(
                              const Radius.circular(20.0),
                            ),
                            // above is per https://github.com/flutter/flutter/issues/5191
                          ),
                          labelText: 'separate,  with,  commas',
                          labelStyle: TextStyle(
                            fontStyle: FontStyle.italic,
                            backgroundColor:
                                Color(0x65dffd02), // was Color(0xffDDFDFC),
                            color: Colors.black87, // was Color(0xffD82E6D),
                            fontSize: 14,
                          ),
                        ),
                        onTagChanged: (value) {
                          setState(() {
                            qOne.add(value);
                          });
                        },
                        tagBuilder: (context, index) => _Chip(
                          index: index,
                          label: qOne[index],
                          onDeleted: onDelete,
                        ),
                      ),
                    ),
                    // END code from material_tag_editor

                    SuperDivider(),
 

Продолжение (пропущено Q2 — Q9):

 SuperDivider(),
                    RichText(
                      text: TextSpan(
                        style: TextStyle(
                          color: Colors.blue,
                        ),
                        children: <TextSpan>[
                          TextSpan(
                            text:
                                'Q10 - via FormBuilder's FormBuilderTextField', // [ 9 ​]
                            style: TextStyle(
                              fontWeight: FontWeight.bold,
                              fontSize: 16.0,
                            ),
                          ),
                          TextSpan(
                            text: '  (optional)',
                            style: TextStyle(
                              fontWeight: FontWeight.normal,
                              fontStyle: FontStyle.italic,
                              fontSize: 14.0,
                              color: Colors.black54,
                            ), // was 'misleading or inaccurate?',
                          ),
                        ],
                      ),
                    ),
                    GavTextField(
                      maxCharLength: 1200,
                      fieldAttribute: 'qTen',
                      fieldLabelText:
                          'Be honest amp; kind.', // was 'Be honest, but kind.',
                    ),
                    SuperDivider(),
                    Padding(
                      padding: const EdgeInsets.symmetric(vertical: 16.0),
                      child: Row(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: [
                          ElevatedButton(
                            style: ElevatedButton.styleFrom(
                                primary: Colors.purple,
                                padding: EdgeInsets.symmetric(
                                    horizontal: 50, vertical: 20),
                                textStyle: TextStyle(
                                    fontSize: 20, fontWeight: FontWeight.bold)),
                            onPressed: () {
                              Alert(
                                context: context,
                                style: alertStyle,
                                title: 'Two quick things...',
                                desc: ' ',
                                content: Column(
                                  children: <Widget>[
                                    RichText(
                                      text: TextSpan(
                                        style: TextStyle(
                                          color: Colors.blue,
                                        ),
                                        children: <TextSpan>[
                                          TextSpan(
                                            text:
                                                'Q11 - via FormBuilder's FormBuilderRadioGroup', // [ 10 ​]
                                            style: TextStyle(
                                              fontWeight: FontWeight.bold,
                                              fontSize: 16.0,
                                            ),
                                          ),
                                        ],
                                      ),
                                    ),
                                    FormBuilderRadioGroup(
                                      name: 'qEleven',
                                      decoration: const InputDecoration(
                                        border: InputBorder.none,
                                      ),
                                      orientation: OptionsOrientation.vertical,
                                      onChanged: _onChanged,
                                      options: [
                                        FormBuilderFieldOption(
                                          value: 'N',
                                          child: RichText(
                                            text: TextSpan(
                                              style: TextStyle(
                                                color: Colors.black,
                                              ),
                                              children: <TextSpan>[
                                                TextSpan(
                                                  text: 'No', // [ 10 ​]
                                                  style: TextStyle(
                                                    fontWeight: FontWeight.w500,
                                                    fontSize: 16.0,
                                                  ),
                                                ),
                                              ],
                                            ),
                                          ),
                                        ),
                                        FormBuilderFieldOption(
                                          value: 'YesSometimes',
                                          child: RichText(
                                            text: TextSpan(
                                              style: TextStyle(
                                                color: Colors.black,
                                              ),
                                              children: <TextSpan>[
                                                TextSpan(
                                                  text:
                                                      'Yes, sometimes', // [ 10 ​]
                                                  style: TextStyle(
                                                    fontWeight: FontWeight.w500,
                                                    fontSize: 16.0,
                                                  ),
                                                ),
                                              ],
                                            ),
                                          ),
                                        ),
                                        FormBuilderFieldOption(
                                          value: 'YesDaily',
                                          child: RichText(
                                            text: TextSpan(
                                              style: TextStyle(
                                                color: Colors.black,
                                              ),
                                              children: <TextSpan>[
                                                TextSpan(
                                                  text: 'Yes, daily', // [ 10 ​]
                                                  style: TextStyle(
                                                    fontWeight: FontWeight.w500,
                                                    fontSize: 16.0,
                                                  ),
                                                ),
                                              ],
                                            ),
                                          ),
                                        ),
                                      ],
                                    ),
                                  ],
                                ),
                                buttons: [
                                  DialogButton(
                                    onPressed: () {
                                      Alert(
                                          context: context,
                                          style: alertStyle,
                                          title: 'And lastly:',
                                          desc: '',
                                          content: Column(
                                            children: <Widget>[
                                              Row(
                                                mainAxisAlignment:
                                                    MainAxisAlignment.start,
                                                children: [
                                                  RichText(
                                                    text: TextSpan(
                                                      style: TextStyle(
                                                        color: Colors.blue,
                                                      ),
                                                      children: <TextSpan>[
                                                        TextSpan(
                                                          text:
                                                              ' Q12 - via FormBuilder's', // [ 10 ​]
 

И, наконец, (пропущенный Q12):

 buttons: [
                                            DialogButton(
                                              // BEGIN submit form when button pressed per 4.0.2 Readme and video https://www.youtube.com/watch?v=7FBELQq808M
                                              onPressed: () {
                                                _newnewFormbuilderKey
                                                    .currentState
                                                    .save();
                                                if (_newnewFormbuilderKey
                                                    .currentState
                                                    .validate()) {
                                                  print(_newnewFormbuilderKey
                                                      .currentState.value);
                                                  print(
                                                    '  >>> Q1's value via separate print: {$qOne}',
                                                  );
                                                  print(
                                                    '  >>> Q3's value via separate print: {$qThree}',
                                                  );
                                                  print(
                                                    '   >>> Q11's value via separate print: {$qEleven}',
                                                  );
                                                  print(
                                                    '   >>> Q12's value via separate print: {$qTwelve}',
                                                  );
                                                  //print(_newFormbuilderKey.currentState.privacyChoice.value);
                                                } else {
                                                  print("validation failed");
                                                }
                                              },

                                              // END submit form when button pressed per 4.0.2 Readme and video https://www.youtube.com/watch?v=7FBELQq808M

                                              child: Text(
                                                "Finish Posting",
                                                style: TextStyle(
                                                  color: Colors.white,
                                                  fontSize: 20,
                                                ),
                                              ),
                                            )
                                          ]).show();
                                    },
                                    child: Text(
                                      "Next >",
                                      style: TextStyle(
                                        color: Colors.white,
                                        fontSize: 20,
                                      ),
                                    ),
                                  )
                                ],
                              ).show();
                            },
                            child: Text(
                              'Post',
                              style: TextStyle(
                                color: Colors.white,
                                fontSize: 20,
                              ),
                            ),
                          ),
                        ],
                      ),
                    ),
 

Спасибо!

Ответ №1:

Пакет flutter form Builder автоматически извлекает форму-предок, чтобы добавить в них значения полей. Но поскольку поля вашей формы теперь находятся в диалоговом окне, они не гарантированно находятся внутри родительского макета, из которого был вызван диалог.

Ссылка из документации flutter (ссылка)

 This function takes a builder which typically builds a Dialog widget. 
Content below the dialog is dimmed with a ModalBarrier. The widget returned by the
builder does not share a context with the location that showDialog is originally
called from. Use a StatefulBuilder or a custom StatefulWidget if the dialog needs
to update dynamically.
 

Вместо этого вы можете сохранить значение этих полей в состоянии вашего виджета с отслеживанием состояния, а затем объединить все значения для будущих операций. Поскольку вы уже сохраняете их в переменной qEleven , и qTwelve вы можете использовать ее позже.

Вот фрагмент кода, делающий это для qEleven (сравните с этим разделом кода в вопросе выше):

 FormBuilderRadioGroup(
                                      name: 'qEleven',
                                      decoration: const InputDecoration(
                                        border: InputBorder.none,
                                      ),
                                      orientation: OptionsOrientation.vertical,
                                      onChanged: (val) {
                                        print(val);
                                        qEleven = val;
                                      },
                                      options: [
                                        FormBuilderFieldOption(
                                          value: 'N',
                                          child: RichText(
                                            text: TextSpan(
                                              style: TextStyle(
                                                color: Colors.black,
                                              ),
                                              children: <TextSpan>[
                                                TextSpan(
                                                  text: 'No', // [ 10 ​]
                                                  style: TextStyle(
                                                    fontWeight: FontWeight.w500,
                                                    fontSize: 16.0,
                                                  ),
                                                ),
                                              ],
                                            ),
                                          ),
                                        ),
 

А вот скриншот, на котором показаны различия между кодом to в вопросе (слева) и кодом, основанным на ответе (справа):

скриншот, показывающий различия в коде

Еще одна вещь, которую можно сделать, — это изменить пакет form builder, чтобы он также принимал состояние, но он может сломаться, если вы обращаетесь к размонтированному состоянию.