#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;