Home > Net >  Radio button change when select next radio button in listview flutter
Radio button change when select next radio button in listview flutter

Time:09-09

I have a problem with the listview builder with the radio button. I used two listview builders first one for questions and the second for the answers list but the problem arrived in the second listview builder with a radio button example: I have 3 questions and I select option b answer for question first so all question answers are selected b and after that when I select next question answer c then all question answers select c in the radio button

please help me I shared my code below

class SurveyScreen extends StatefulWidget {
  const SurveyScreen({Key? key}) : super(key: key);

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

Future<GetSurveyData> getData() async {
  GetSurveyData? getSurveyData;
  var response = await http.get(
    Uri.https('ehubapi.ascs.link', 'api/GetUserSurveyData'),
    headers: {
      "content-type": "application/json",
      "accept": "application/json",
"Authorization":
          "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy9304M2E4LTAwNTA1NjQ3N2Y5YyIsIlhhZlNlY3VyaXR5QXV0aFBhc3NlZCI6IlhhZlNlY3VyaXR5QXV0aFBhc3NlZCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL25hbWUiOiJtdXN0YWZhLnNhZWVkIiwiWGFmU2VjdXJpdHkiOiJYYWZTZWN1cml0eSIsIlhhZkxvZ29uUGFyYW1zIjoicTFZcUxVNHQ4a3ZNVFZXeVVzb3RMUzVKVEV2VUswNU1UVTFSMGxFcVNDd3VMczh2U2dGS0dRYWFGQnViK0ZRbzFRSUEiLCJleHAiOjE2NjI3ODI3MDV9.OFZho2bs_ZIR_bcPdL9fXHSmWH5_K58E66OV0VDFOvc"
    },
  );

  var jsonResponse = json.decode(response.body);
  print(jsonResponse);
  getSurveyData = GetSurveyData.fromJson(jsonResponse);

  return getSurveyData;
}

class _SurveyScreenState extends State<SurveyScreen> {
  var groupValue = -1;

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: const Color(0xff98C337),
      body: Stack(
        children: [
          SingleChildScrollView(
              child: Container(
            alignment: Alignment.center,
            padding: const EdgeInsets.only(
                // top: MediaQuery.of(context).size.height * 0.5,
                top: 50,
                left: 30,
                right: 30),
            child: Column(
              children: [
                Align(
                  alignment: Alignment.centerLeft,
                  child: IconButton(
                    onPressed: () {
                      Navigator.of(context).pop();
                    },
                    icon: const Icon(Icons.arrow_back_ios),
                  ),
                ),
                const SizedBox(
                  height: 30,
                ),
                FutureBuilder(
                    future: getData(),
                    builder: (context, AsyncSnapshot<GetSurveyData> snapshot) {
                      if (snapshot.data != null) {
                        return Column(
                          children: [
                            Align(
                                alignment: Alignment.centerLeft,
                                child: Text(
                                  snapshot.data?.data.enabledSurveys[0]
                                          .englishName ??
                                      "",
                                  style: const TextStyle(
                                      color: Colors.black,
                                      fontSize: 25,
                                      fontFamily: 'Josefin Sans',
                                      fontWeight: FontWeight.w700),
                                )),
                            const SizedBox(
                              height: 10,
                            ),
                            Align(
                                alignment: Alignment.centerLeft,
                                child: Text(
                                  snapshot.data?.data.enabledSurveys[0]
                                          .arabicName ??
                                      "",
                                  style: const TextStyle(
                                      color: Colors.black, fontSize: 12),
                                )),
                            const SizedBox(
                              height: 30,
                            ),
                            SizedBox(
                              height: 500,
                              child: Align(
                                alignment: Alignment.center,
                                child: ListView.builder(
                                  shrinkWrap: true,
                                  padding: const EdgeInsets.all(0.0),
                                  scrollDirection: Axis.horizontal,
                                  // itemCount: userDashboard.joinedUpcomingClasses.length,
                                  itemCount: snapshot.data?.data
                                      .enabledSurveys[0].questions.length,
                                  itemBuilder:
                                      (BuildContext context, int index) {
                                    return SizedBox(
                                      width: 300,
                                      child: Card(
                                          color: Colors.white,
                                          child: Padding(
                                            padding: const EdgeInsets.all(10),
                                            child: Column(
                                              children: [
                                                Text(
                                                  snapshot
                                                          .data
                                                          ?.data
                                                          .enabledSurveys[0]
                                                          .questions[index]
                                                          .englishText ??
                                                      '',
                                                  style: const TextStyle(
                                                      color: Colors.black,
                                                      fontSize: 18,
                                                      fontFamily:
                                                          'Josefin Sans',
                                                      fontWeight:
                                                          FontWeight.w700),
                                                ),
                                                SizedBox(
                                                  height: 10,
                                                ),
                                                Text(
                                                    snapshot
                                                            .data
                                                            ?.data
                                                            .enabledSurveys[0]
                                                            .questions[index]
                                                            .arabicText ??
                                                        '',
                                                    style: const TextStyle(
                                                        color: Colors.grey,
                                                        fontSize: 12)),
                                                Builder(builder: (context) {
                                                  if (snapshot
                                                          .data
                                                          ?.data
                                                          .enabledSurveys[0]
                                                          .questions[index]
                                                          .answers
                                                          .length ==
                                                      0) {
                                                    return textField();
                                                  } else {
                                                    return answeringListData(
                                                        snapshot
                                                                .data
                                                                ?.data
                                                                .enabledSurveys[
                                                                    0]
                                                                .questions[
                                                                    index]
                                                                .answers ??
                                                            []);
                                                  }
                                                }),
                                              ],
                                            ),
                                          )),
                                    );
                                  },
                                ),
                              ),
                            ),
                          ],
                        );
                      } else {
                        return SizedBox(
                          height: double.infinity,
                          child: Center(
                              child: Column(
                            //Horizontal
                            crossAxisAlignment: CrossAxisAlignment.center,
                            //Vertical
                            mainAxisAlignment: MainAxisAlignment.center,
                            children: const [
                              CircularProgressIndicator(),
                              Text("Loading..."),
                            ],
                          )),
                        );
                      }
                    }),
                const SizedBox(
                  height: 20,
                ),
              ],
            ),
          ))
        ],
      ),
    );
  }

  Widget answeringListData(List<Answers> answers) {
    return SizedBox(
      height: 200,
      child: ListView.builder(
        padding: EdgeInsets.zero,
        physics: ClampingScrollPhysics(),
        itemCount: answers.length,
        itemBuilder: (context, index) => ButtonBar(
          buttonPadding: EdgeInsets.zero,
          alignment: MainAxisAlignment.spaceBetween,
          children: <Widget>[
            Text(answers[index].englishText,
                style: const TextStyle(
                    fontSize: 12,
                    fontWeight: FontWeight.bold,
                    color: Colors.black)),
            Radio(
              groupValue: groupValue,
              value: index,
              onChanged: (newValue) =>
                  setState(() => groupValue = newValue as int),
            ),
          ],
        ),
      ),
    );
  }

  Widget textField() {
    return const Flexible(
      child: Align(
        alignment: Alignment.topCenter,
        child: TextField(
            textAlignVertical: TextAlignVertical.center,
            decoration: InputDecoration(
              enabledBorder: UnderlineInputBorder(
                borderSide: BorderSide(color: Colors.grey),
              ),
              focusedBorder: UnderlineInputBorder(
                borderSide: BorderSide(color: Colors.grey),
              ),
              border: UnderlineInputBorder(
                borderSide: BorderSide(color: Colors.grey),
              ),
              hintText: "Please Type Your Answer Here...",
              hintStyle: TextStyle(color: Colors.black),
            ),
            style: TextStyle(color: Colors.black),
            textInputAction: TextInputAction.next),
      ),
    );
  }
}

My Model Class

class GetSurveyData {
  GetSurveyData({
    required this.message,
    required this.data,
  });
  late final String message;
  late final Data data;

  GetSurveyData.fromJson(Map<String, dynamic> json){
    message = json['message'];
    data = Data.fromJson(json['data']);
  }

  Map<String, dynamic> toJson() {
    final _data = <String, dynamic>{};
    _data['message'] = message;
    _data['data'] = data.toJson();
    return _data;
  }
}

class Data {
  Data({
    required this.doneBy,
    required this.userName,
    this.email,
    this.mobileNumber,
    required this.fullNameInEnglish,
    required this.fullNameInArabic,
    required this.enabledSurveys,
    required this.shops,
  });
  late final String doneBy;
  late final String userName;
  late final Null email;
  late final Null mobileNumber;
  late final String fullNameInEnglish;
  late final String fullNameInArabic;
  late final List<EnabledSurveys> enabledSurveys;
  late final List<Shops> shops;

  Data.fromJson(Map<String, dynamic> json){
    doneBy = json['doneBy'];
    userName = json['userName'];
    email = null;
    mobileNumber = null;
    fullNameInEnglish = json['fullNameInEnglish'];
    fullNameInArabic = json['fullNameInArabic'];
    enabledSurveys = List.from(json['enabledSurveys']).map((e)=>EnabledSurveys.fromJson(e)).toList();
    shops = List.from(json['shops']).map((e)=>Shops.fromJson(e)).toList();
  }

  Map<String, dynamic> toJson() {
    final _data = <String, dynamic>{};
    _data['doneBy'] = doneBy;
    _data['userName'] = userName;
    _data['email'] = email;
    _data['mobileNumber'] = mobileNumber;
    _data['fullNameInEnglish'] = fullNameInEnglish;
    _data['fullNameInArabic'] = fullNameInArabic;
    _data['enabledSurveys'] = enabledSurveys.map((e)=>e.toJson()).toList();
    _data['shops'] = shops.map((e)=>e.toJson()).toList();
    return _data;
  }
}

class EnabledSurveys {
  EnabledSurveys({
    required this.referenceTemplate,
    required this.englishName,
    required this.arabicName,
    required this.sequence,
    required this.questions,
  });
  late final String referenceTemplate;
  late final String englishName;
  late final String arabicName;
  late final int sequence;
  late final List<Questions> questions;

  EnabledSurveys.fromJson(Map<String, dynamic> json){
    referenceTemplate = json['referenceTemplate'];
    englishName = json['englishName'];
    arabicName = json['arabicName'];
    sequence = json['sequence'];
    questions = List.from(json['questions']).map((e)=>Questions.fromJson(e)).toList();
  }

  Map<String, dynamic> toJson() {
    final _data = <String, dynamic>{};
    _data['referenceTemplate'] = referenceTemplate;
    _data['englishName'] = englishName;
    _data['arabicName'] = arabicName;
    _data['sequence'] = sequence;
    _data['questions'] = questions.map((e)=>e.toJson()).toList();
    return _data;
  }
}

class Questions {
  Questions({
    required this.referenceQuestion,
    required this.englishText,
    required this.arabicText,
    required this.questionType,
    required this.required,
    required this.evidencePhotoRequired,
    required this.sequence,
    required this.answers,
  });
  late final String referenceQuestion;
  late final String englishText;
  late final String arabicText;
  late final String questionType;
  late final bool required;
  late final bool evidencePhotoRequired;
  late final int sequence;
  late final List<Answers> answers;

  Questions.fromJson(Map<String, dynamic> json){
    referenceQuestion = json['referenceQuestion'];
    englishText = json['englishText'];
    arabicText = json['arabicText'];
    questionType = json['questionType'];
    required = json['required'];
    evidencePhotoRequired = json['evidencePhotoRequired'];
    sequence = json['sequence'];
    answers = List.from(json['answers']).map((e)=>Answers.fromJson(e)).toList();
  }

  Map<String, dynamic> toJson() {
    final _data = <String, dynamic>{};
    _data['referenceQuestion'] = referenceQuestion;
    _data['englishText'] = englishText;
    _data['arabicText'] = arabicText;
    _data['questionType'] = questionType;
    _data['required'] = required;
    _data['evidencePhotoRequired'] = evidencePhotoRequired;
    _data['sequence'] = sequence;
    _data['answers'] = answers.map((e)=>e.toJson()).toList();
    return _data;
  }
}

class Answers {
  Answers({
    required this.referenceAnswer,
    required this.englishText,
    required this.arabicText,
    required this.evidencePhotoRequired,
    required this.commentRequired,
    required this.sequence,
  });
  late final String referenceAnswer;
  late final String englishText;
  late final String arabicText;
  late final bool evidencePhotoRequired;
  late final bool commentRequired;
  late final int sequence;

  Answers.fromJson(Map<String, dynamic> json){
    referenceAnswer = json['referenceAnswer'];
    englishText = json['englishText'];
    arabicText = json['arabicText'];
    evidencePhotoRequired = json['evidencePhotoRequired'];
    commentRequired = json['commentRequired'];
    sequence = json['sequence'];
  }

  Map<String, dynamic> toJson() {
    final _data = <String, dynamic>{};
    _data['referenceAnswer'] = referenceAnswer;
    _data['englishText'] = englishText;
    _data['arabicText'] = arabicText;
    _data['evidencePhotoRequired'] = evidencePhotoRequired;
    _data['commentRequired'] = commentRequired;
    _data['sequence'] = sequence;
    return _data;
  }
}

class Shops {
  Shops({
    required this.id,
    required this.title,
    required this.nameInEnglish,
    required this.nameInArabic,
    required this.addressInEnglish,
    required this.addressInArabic,
    required this.contactNumber,
    required this.latitude,
    required this.longitude,
    required this.channel,
  });
  late final String id;
  late final String title;
  late final String nameInEnglish;
  late final String nameInArabic;
  late final String addressInEnglish;
  late final String addressInArabic;
  late final String contactNumber;
  late final double latitude;
  late final double longitude;
  late final String channel;

  Shops.fromJson(Map<String, dynamic> json){
    id = json['id'];
    title = json['title'];
    nameInEnglish = json['nameInEnglish'];
    nameInArabic = json['nameInArabic'];
    addressInEnglish = json['addressInEnglish'];
    addressInArabic = json['addressInArabic'];
    contactNumber = json['contactNumber'];
    latitude = json['latitude'];
    longitude = json['longitude'];
    channel = json['channel'];
  }

  Map<String, dynamic> toJson() {
    final _data = <String, dynamic>{};
    _data['id'] = id;
    _data['title'] = title;
    _data['nameInEnglish'] = nameInEnglish;
    _data['nameInArabic'] = nameInArabic;
    _data['addressInEnglish'] = addressInEnglish;
    _data['addressInArabic'] = addressInArabic;
    _data['contactNumber'] = contactNumber;
    _data['latitude'] = latitude;
    _data['longitude'] = longitude;
    _data['channel'] = channel;
    return _data;
  }
}

CodePudding user response:

The problem is that you're using one state, groupValue for all the answers for all questions. To solve it split groupValue between the questions. A Map<int, int> would do that where the key is the question index and the value is the answer index. It would be like the following:

Pass the question index to answeringListData and set the map accordingly.

  Widget answeringListData(int questionIndex, List<Answers> answers) {
    return SizedBox(
      height: 200,
      child: ListView.builder(
        padding: EdgeInsets.zero,
        physics: ClampingScrollPhysics(),
        itemCount: answers.length,
        itemBuilder: (context, index) => ButtonBar(
          buttonPadding: EdgeInsets.zero,
          alignment: MainAxisAlignment.spaceBetween,
          children: <Widget>[
            Text(answers[index].englishText,
                style: const TextStyle(
                    fontSize: 12,
                    fontWeight: FontWeight.bold,
                    color: Colors.black)),
            Radio(
              groupValue: groupValue[questionIndex],
              value: index,
              onChanged: (newValue) =>
                  setState(() => groupValue[questionIndex] = newValue!),
            ),
          ],
        ),
      ),
    );
  }

The call site is going to be like this:

answeringListData(index, snapshot.data?.data.enabledSurveys[0]
    .questions[index].answers ??[]);

And here is the groupValue map declaration from just int to a Map:

final groupValue = <int, int>{};

Here's the result:

enter image description here

CodePudding user response:

This answer is base on you model.

First change your question model to this:

class Questions {
  Questions({
    required this.referenceQuestion,
    required this.englishText,
    required this.arabicText,
    required this.questionType,
    required this.required,
    required this.evidencePhotoRequired,
    required this.sequence,
    required this.answers,
    required this.groupValue,
  });
  late final String referenceQuestion;
  late final String englishText;
  late final String arabicText;
  late final String questionType;
  late final bool required;
  late final bool evidencePhotoRequired;
  late final int sequence;
  late final List<Answers> answers;
  late final int groupValue;

  Questions.fromJson(Map<String, dynamic> json) {
    referenceQuestion = json['referenceQuestion'];
    englishText = json['englishText'];
    arabicText = json['arabicText'];
    questionType = json['questionType'];
    required = json['required'];
    evidencePhotoRequired = json['evidencePhotoRequired'];
    sequence = json['sequence'];
    groupValue = -1;
    answers =
        List.from(json['answers']).map((e) => Answers.fromJson(e)).toList();
  }

  Map<String, dynamic> toJson() {
    final _data = <String, dynamic>{};
    _data['referenceQuestion'] = referenceQuestion;
    _data['englishText'] = englishText;
    _data['arabicText'] = arabicText;
    _data['questionType'] = questionType;
    _data['required'] = required;
    _data['evidencePhotoRequired'] = evidencePhotoRequired;
    _data['sequence'] = sequence;
    // _data['groupValue'] = groupValue;
    _data['answers'] = answers.map((e) => e.toJson()).toList();

    return _data;
  }
}

then change your answeringListData to this, as you can see I use StatefulBuilder, in this way your hole code wont rebuild and every time your api wont call:

Widget answeringListData(
      List<Answers> answers, int questionIndex, List<Questions>? questions) {
    return SizedBox(
      height: 200,
      child: StatefulBuilder(builder: (context, innerSetState) {
        return ListView.builder(
          padding: EdgeInsets.zero,
          physics: ClampingScrollPhysics(),
          itemCount: answers.length,
          itemBuilder: (context, index) => ButtonBar(
            buttonPadding: EdgeInsets.zero,
            alignment: MainAxisAlignment.spaceBetween,
            children: <Widget>[
              Text(answers[index].englishText,
                  style: const TextStyle(
                      fontSize: 12,
                      fontWeight: FontWeight.bold,
                      color: Colors.black)),
              Radio(
                groupValue: questions![questionIndex].groupValue,
                value: index,
                onChanged: (newValue) => innerSetState(() {
                  var oldQuestions = questions![questionIndex];
                  var newQuestion = Questions(
                    referenceQuestion: oldQuestions.referenceQuestion,
                    englishText: oldQuestions.englishText,
                    arabicText: oldQuestions.arabicText,
                    questionType: oldQuestions.questionType,
                    required: oldQuestions.required,
                    evidencePhotoRequired: oldQuestions.evidencePhotoRequired,
                    sequence: oldQuestions.sequence,
                    answers: oldQuestions.answers,
                    groupValue: newValue as int,
                  );
                  questions[questionIndex] = newQuestion;
                }),
              ),
            ],
          ),
        );
      }),
    );
  }

then pass answeringListData like this in your main widget :

...
} else {
   return answeringListData(
      snapshot.data?.data.enabledSurveys[0].questions[index].anwers ?? [],
      index,
      snapshot.data?.data.enabledSurveys[0].questions);
}

enter image description here

  • Related