Каков наилучший способ динамической загрузки полей формы в флаттере? - PullRequest
2 голосов
/ 02 апреля 2019

Мои TextFormFields не работают должным образом и заставляют страницу перестраиваться, когда я нажимаю на них, и клавиатура не отображается полностью.

У меня есть форма с двумя выпадающими списками и несколькими текстовыми полями. Выпадающие списки определяют, какие текстовые поля отображаются. Я определяю это следующим образом:

Form(
                    key: _formKey,
                    child: Flex(
                      direction: Axis.vertical,
                      children: <Widget>[
                        //category field
                        new FormField<String>(
                            validator: this.validateField,
                            builder: (FormFieldState<String> state) {
                              return new DropdownButtonHideUnderline(
                                  child: DropdownButton<String>(
                                hint: new Text('Select Category'),
                                value: exercise.categoryName,
                                items: categoryNameList.map((String value) {
                                  return new DropdownMenuItem<String>(
                                    value: value,
                                    child: new Text(value),
                                  );
                                }).toList(),
                                onChanged: (String val) {
                                  setState(() {
                                    //save category name to the exercise object to be saved
                                    exercise.categoryName = val;
                                    state.didChange(val);
                                    // reset exercise dropdown when switching categories
                                    exercise = new Exercise(
                                        categoryName: val, cardioImperial: -1);
                                    // get index of the selected category to be able to load the correct
                                    // exercise list
                                    _exerciseSelectedTextIndex =
                                        categoryNameList.indexOf(val);
                                    _exerciseSelectedList =
                                        categoryList[_exerciseSelectedTextIndex]
                                            .exerciseNames;
                                  });
                                },
                              ));
                            }),

                        // only load the exercise list once the category is selected
                        _exerciseSelectedList != null
                            ? Container(
                                child:
                                    Flex(direction: Axis.vertical, children: <
                                        Widget>[
                                new FormField(
                                    validator: this.validateField,
                                    builder: (FormFieldState<String> state) {
                                      return new DropdownButtonHideUnderline(
                                          child: DropdownButton<String>(
                                        hint: new Text('Select Exercise'),
                                        value: exercise.name,
                                        items: _exerciseSelectedList
                                            .map((String value) {
                                          return new DropdownMenuItem<String>(
                                            value: value,
                                            child: new Text(value),
                                          );
                                        }).toList(),
                                        onChanged: (String val) {
                                          setState(() {
                                            exercise.name = val;
                                            state.didChange(val);
                                          });
                                        },
                                      ));
                                    }),
                              ]))
                            : Container(),

                        //if cardio load time/length else load reps/quantity
                        _exerciseSelectedList != null
                            ? categoryList[_exerciseSelectedTextIndex].cardio ==
                                    true
                                ? Flex(direction: Axis.vertical, children: <
                                    Widget>[
                                    Row(
                                        mainAxisAlignment:
                                            MainAxisAlignment.center,
                                        children: <Widget>[
                                          SizedBox(
                                              width: 75.0,
                                              child: TextFormField(
                                                validator: this.validateField,
                                                onSaved: (value) => exercise
                                                    .cardioLength = value,
                                                keyboardType:
                                                    TextInputType.number,
                                                decoration: InputDecoration(
                                                  hintText: 'Length',
                                                ),
                                              )),
                                          new Radio(
                                            groupValue: exercise.cardioImperial,
                                            value: 1,
                                            onChanged: (value) => setState(() {
                                                  exercise.cardioImperial =
                                                      value;
                                                }),
                                          ),
                                          new Text('Miles'),
                                          new Radio(
                                            groupValue: exercise.cardioImperial,
                                            value: 2,
                                            onChanged: (value) => setState(() {
                                                  exercise.cardioImperial =
                                                      value;
                                                }),
                                          ),
                                          new Text('KM')
                                        ]),

                                    // time fields
                                    Row(
                                        mainAxisAlignment:
                                            MainAxisAlignment.center,
                                        children: <Widget>[
                                          Padding(
                                            padding: const EdgeInsets.all(8.0),
                                            child: SizedBox(
                                              width: 30.0,
                                              child: TextFormField(
                                                validator: this.validateField,
                                                onSaved: (value) =>
                                                    exercise.hh = value,
                                                keyboardType:
                                                    TextInputType.number,
                                                decoration: InputDecoration(
                                                  hintText: 'HH',
                                                ),
                                              ),
                                            ),
                                          ),
                                          Padding(
                                            padding: const EdgeInsets.all(8.0),
                                            child: SizedBox(
                                              width: 30.0,
                                              child: TextFormField(
                                                validator: this.validateField,
                                                onSaved: (value) =>
                                                    exercise.mm = value,
                                                keyboardType:
                                                    TextInputType.number,
                                                decoration: InputDecoration(
                                                  hintText: 'MM',
                                                ),
                                              ),
                                            ),
                                          ),
                                          Padding(
                                            padding: const EdgeInsets.all(8.0),
                                            child: SizedBox(
                                              width: 30.0,
                                              child: TextFormField(
                                                validator: this.validateField,
                                                onSaved: (value) =>
                                                    exercise.ss = value,
                                                keyboardType:
                                                    TextInputType.number,
                                                decoration: InputDecoration(
                                                  hintText: 'SS',
                                                ),
                                              ),
                                            ),
                                          )
                                        ])
                                  ])

                                // if not cardio, load quantity/reps
                                : Flex(
                                    direction: Axis.vertical,
                                    children: <Widget>[
                                        SizedBox(
                                          width: 75.0,
                                          child: TextFormField(
                                            onSaved: (value) =>
                                                exercise.quantity = value,
                                            keyboardType: TextInputType.number,
                                            decoration: InputDecoration(
                                              hintText: 'Weight',
                                            ),
                                          ),
                                        ),

                                        // reps field
                                        Padding(
                                          padding: const EdgeInsets.all(8.0),
                                          child: SizedBox(
                                            width: 50.0,
                                            child: TextFormField(
                                              onSaved: (value) =>
                                                  exercise.reps = value,
                                              keyboardType:
                                                  TextInputType.number,
                                              decoration: InputDecoration(
                                                hintText: 'Reps',
                                              ),
                                            ),
                                          ),
                                        ),
                                      ])
                            : Container(),
                      ],
                    ))

Я ожидаю, что когда я выберу Cardio (cardio == true), можно будет щелкнуть доступные текстовые поля и ввести данные. Отображаются правильные поля, но вся страница перестраивается, когда я нажимаю на любое из полей текстовой формы. Есть ли лучший способ создать эту страницу, которая бы учитывала ожидаемое поведение?

1 Ответ

1 голос
/ 10 апреля 2019

Проблема возникла из-за того, что ScaffoldState и FormState живут в виджете Stateful, который включал мою форму.

Процесс моего приложения выглядит следующим образом:

Home -> Page1 -> Page2 (с формой)

Изначально ScaffoldState и FormState жили на Page2.Я сохранил тот же поток, но переместил ScaffoldState и FormState на Page1, и я передал их на Page2 для использования в форме.Теперь мой TextFormField не вызывает перестроения, когда я нажимаю на него, и функция сохранения работает, как и ожидалось.

...