RadioListTile Внутри StatefulBuilder не отменяет выбор других параметров внутри RadioListTile

#flutter #dart #flutter-layout

#flutter #dart #flutter-layout

Вопрос:

Я создал функцию, в которой я создаю разные виджеты, в этой функции я создаю radioListTile для каждого ответа типа radio внутри вопроса. (перебираю все ответы и создаю radioListTile для каждого ответа).

Я обернул этот radioListtile внутри statefulBuilder, чтобы он не создавал заново или не влиял на весь экран, и использовал метод setstate для изменения / установки значения.

проблема в том, что когда я выбираю любой другой параметр / значение внутри этого radioListTile, он не отменяет выбор предыдущего параметра (означает, что я могу выбрать все параметры внутри radioListTile).

пожалуйста, проверьте мой код ниже для создания виджета.

 List<Widget> getAnswerWidget(Question objQuestion) {
    // list of all answers inside a question
    List<Answer> answerList = objQuestion.answers;
    // list of widgets for each question
    List<Widget> answerWidget = [];
    // fetching answer type for switch case inside generating answers method
    var answerType = answerList[0].answerType.toUpperCase();

    switch (answerType) {
      case ("TEXT"): // if answer type is equal to text
        var index = listAnswers
            .indexWhere((pair) => pair['Key'] == objQuestion.questionId);
        answerWidget.add(StatefulBuilder(
            builder: (BuildContext context, StateSetter setState) {
          return Container(
            child: Padding(
              padding: EdgeInsets.all(10.0),
              child: new Theme(
                data: new ThemeData(
                  primaryColor: Color.fromRGBO(223, 0, 61, 1),
                  primaryColorDark: Color.fromRGBO(223, 0, 61, 1),
                ),
                child: TextField(
                  decoration: new InputDecoration(
                      border: new OutlineInputBorder(
                          borderSide: new BorderSide(
                              color: Color.fromRGBO(223, 0, 61, 1))),
                      hintText: 'This is a question hint',
                      helperText: 'this is a helper text.',
                      labelText: 'Enter text',
                      prefixIcon: const Icon(
                        Icons.question_answer,
                        color: Color.fromRGBO(223, 0, 61, 1),
                      ),
                      prefixText: ' ',
                      suffixText: 'suffix',
                      suffixStyle: const TextStyle(
                          color: Color.fromRGBO(223, 0, 61, 1))),
                ),
              ),
            ),
          );
        }));
        return answerWidget;
        break;

      case ("CHECKBOX"): // if answer type is equal to checkbox
        for (Answer ans in objQuestion.answers) {
          var index =
              listAnswers.indexWhere((pair) => pair['Key'] == ans.answerId);
          answerWidget.add(StatefulBuilder(
              builder: (BuildContext context, StateSetter setState) {
            return Container(
                child: Padding(
              padding: EdgeInsets.all(10.0),
              child: CheckboxListTile(
                title: Text(ans.answerText),
                value: listAnswers[index]['value'],
                onChanged: (val) {
                  setState(() {
                    listAnswers[index]['value'] = val;
                    print(listAnswers[index]['value']);
                  });
                },
                secondary: const Icon(Icons.check),
              ),
            ));
          }));
        }
        return answerWidget;
        break;

      case ("RADIO"): // if answer type is equal to radio (majority of answers are radio)
        var index = listAnswers
            .indexWhere((pair) => pair['Key'] == objQuestion.questionId);
        for (Answer ans in objQuestion.answers) {
          answerWidget.add(StatefulBuilder(
              builder: (BuildContext context, StateSetter setState) {
            return Container(
                child: Padding(
              padding: EdgeInsets.all(10.0),
              child: RadioListTile(
                groupValue: listAnswers[index]['value'],
                title: Text(ans.answerText),
                value: ans.answerId,
                onChanged: (val) {
                  setState(() {
                    listAnswers[index]['value'] = val;
                    // debug
                    print(
                        'listValue: '   listAnswers[index]['value'].toString());
                    print('index: '   index.toString());
                  });
                },
                selected: listAnswers[index]['value'] == ans.answerId,
                secondary: const Icon(Icons.child_care),
              ),
            ));
          }));
        }
        return answerWidget;
        break;

      case ("OPTION"): // if answer type is equal to dropdown/select
        var index = listAnswers
            .indexWhere((pair) => pair['Key'] == objQuestion.questionId);
        List<DropdownMenuItem> _dropdownItems = [];
        for (var i = 0; i < answerList.length; i  ) {
          _dropdownItems.add(DropdownMenuItem(
              value: answerList[i].answerId,
              child: Text(answerList[i].answerText)));
        }
        answerWidget.add(StatefulBuilder(
            builder: (BuildContext context, StateSetter setState) {
          return Container(
            child: Padding(
              padding: EdgeInsets.all(10.0),
              child: DropdownButton(
                  hint: Text('Please Select'),
                  items: _dropdownItems,
                  onChanged: (value) {
                    setState(() {
                      listAnswers[index]['value'] = value;
                      print('value:'   value.toString());
                    });
                  }),
            ),
          );
        }));
        return answerWidget;
        break;

      case ("DATE"): // if answer type is equal to date
        var index = listAnswers
            .indexWhere((pair) => pair['Key'] == objQuestion.questionId);
        answerWidget.add(StatefulBuilder(
            builder: (BuildContext context, StateSetter setState) {
          return Container(
              child: Padding(
                  padding: EdgeInsets.all(10.0),
                  child: MyTextFieldDatePicker(
                      // custom widget inside utils folder
                      labelText: "Date",
                      prefixIcon: Icon(Icons.date_range),
                      suffixIcon: Icon(Icons.arrow_drop_down),
                      lastDate: DateTime.now().add(Duration(days: 366)),
                      firstDate: DateTime.now().add(Duration(days: -366)),
                      initialDate: DateTime.now().add(Duration(days: 1)),
                      onDateChanged: (selectedDate) {
                        listAnswers[index]['value'] = selectedDate;
                      })));
        }));
        return answerWidget;
        break;
    } // end switch answer type cases
    return answerWidget;
  }

  

код для карты генерации (рассматривайте это как место, где я храню ответы / выборки)

 void generateAnswers(List<Question> objQuestions) {
    for (int i = 0; i < objQuestions.length; i  ) {
      if (objQuestions[i].answers[0].answerType.toUpperCase() == 'CHECKBOX') {
        for (Answer ans in objQuestions[i].answers) {
          var keyPair = {
            'Key': ans.answerId,
            'value': false,
          };
          listAnswers.add(keyPair);
        }
      } else if (objQuestions[i].answers[0].answerType.toUpperCase() ==
          'RADIO') {
        var keyPair = {
          'Key': objQuestions[i].questionId,
          'value': 0,
        };
        listAnswers.add(keyPair);
      } else if (objQuestions[i].answers[0].answerType.toUpperCase() ==
          'TEXT') {
        var keyPair = {
          'Key': objQuestions[i].questionId,
          'value': "",
        };
        listAnswers.add(keyPair);
      } else if (objQuestions[i].answers[0].answerType.toUpperCase() ==
          'OPTION') {
        var keyPair = {
          'Key': objQuestions[i].questionId,
          'value': null,
        };
        listAnswers.add(keyPair);
      } else if (objQuestions[i].answers[0].answerType.toUpperCase() ==
          'DATE') {
        var keyPair = {
          'Key': objQuestions[i].questionId,
          'value': TimeOfDay.now(),
        };
        listAnswers.add(keyPair);
      }
    }
  }
  

Примечание: если я удалю answerWidget.add(StatefulBuilder(…)), это приведет к перестройке всего экрана (это решает мою проблему выбора). И если выбрать вариант из последнего вопроса, он снова поднимется наверх.

Комментарии:

1. более подробную информацию об ошибке можно найти здесь. youtu.be/3F5JtNfJYLc заранее благодарю вас. Я уже потратил на это много времени.

2. вы не получаете true и false при нажатии на радио?

3. когда один из них имеет значение true, вы должны обновить другие до false

4. if (val == true) for (int i = 0; i < Список ответов. длина;i ){ listAnswers[index][‘value’] = false; } listAnswers[index][‘value’] = значение;

5. нет, это не помогает

Ответ №1:

Создайте отдельный метод для обработки состояния радиотайла и передайте состояние в качестве параметра этому методу, например

 List<RadioListTile> generateRadioTile(var objQuestion, StateSetter setState){
List<RadioListTile> radioList = [];
for (Answer ans in objQuestion.answers) {
  var index = listAnswers.indexWhere((pair) => pair['key'] == objQuestion.questionId);
  // fetching answer index
  var ansIndex = listAnswers[index]['answer'].indexWhere((pair) => pair['key'] == ans.answerId);
  radioList.add(RadioListTile(
    // key: _key,
    title: Text(ans.answerText),
    value: listAnswers[index]['answer'][ansIndex]['key'],
    groupValue: listAnswers[index]['selectedValue'],
    onChanged: (val) {
      setState(() {
        // making all other answer option selected value to false
        listAnswers[index]['answer'].asMap().forEach(
                (index, keyPair) => keyPair['value'] = false);

        // making current answer option selected value to true
        listAnswers[index]['answer'][ansIndex]['value'] =
        true;

        // setting current selected value to selected answer answerId which is key value
        listAnswers[index]['selectedValue'] = val;

        // printing value for debugging
        print('val: '   val.toString());
        print('ans_index: '   ansIndex.toString());
        print('value: '  
            listAnswers[index]['answer'][ansIndex]['value']
                .toString());
        print('Answer array values :-');
        listAnswers[index]['answer'].asMap().forEach(
                (index, keyPair) => print(keyPair['value']));

        // working with the visibility
        processAnswerLogic(ans.answerLogic);
      });
    },
    secondary: const Icon(Icons.check),
    activeColor: Color.fromRGBO(223, 0, 61, 1),
  ));
}
return radioList;}
  

и в инструкции switch измените свой код, как показано ниже:

 case ("RADIO"): // if answer type is equal to radio (majority of answers are radio)

    answerWidget.add(StatefulBuilder(
        builder: (BuildContext context, StateSetter setState) {
          return Container(
              child: Padding(
                  padding: EdgeInsets.all(10.0),
                  child: Column(
                    children: generateRadioTile(objQuestion, setState),
                  )));
        }));
    return answerWidget;
    break;