Search code examples
flutterdartflutter-layoutradio-button

How to select one checkbox in listView inside listview in Flutter


how to select one checkbox in each answer for each question. so that each question can only be chosen one answer. this is my data and this is my code

This is data example:

    List<dynamic> survey = [
  {
    "id": 1,
    "question":"Question1",
    "answer": [
      {"id": 1, "name": "Option A"},
      {"id": 2, "name": "Option B"},
      {"id": 3, "name": "Option C"},
      {"id": 4, "name": "Option D"}
    ],
  },
  {
    "id": 2,
    "question":
        "Question2",
    "answer": [
      {"id": 1, "name": "Option A"},
      {"id": 2, "name": "Option B"},
      {"id": 3, "name": "Option C"},
      {"id": 4, "name": "Option D"}
    ],
  },
];

This is my code:

   bool isSelected = false;

  onSelected(value) {
    setState(() {
      isSelected = value!;
    });
  }

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      shrinkWrap: true,
      itemCount: survey.length,
      itemBuilder: (BuildContext context, int index) {
        var number = index + 1;
        var listAnswer = survey[index]["answer"];
        return Container(
          padding: EdgeInsets.all(10),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              SizedBox(
                width: MediaQuery.of(context).size.width * 0.9,
                child: Text(
                  survey[index]["question"],
                  maxLines: 5,
                  overflow: TextOverflow.ellipsis,
                ),
              ),
              SizedBox(height: 10),
              ListView.builder(
                shrinkWrap: true,
                itemCount: listAnswer.length,
                itemBuilder: (BuildContext context, int index) {
                  return Container(
                    margin: EdgeInsets.only(bottom: 10),
                    child: ListTile(
                      title: Text(listAnswer[index]["name"]),
                      trailing: Checkbox(
                        checkColor: Colors.white,
                        value: isSelected,
                        shape: CircleBorder(),
                        onChanged: (bool? value) {
                          onSelected(value);
                        },
                      ),
                    ),
                  );
                },
              )
            ],
          ),
        );
      },
    );
  }

Solution

  • It would be easier with model class. I am using a map to store the selected answer.

      Map<String, int> selectedAnswer = {};
    

    Method checking whether current answer is selected or not.

      bool isSelected(String qustion, int answerID) {
        if (selectedAnswer.containsKey(qustion) &&
            selectedAnswer[qustion] == answerID) {
          return true;
        }
        return false;
      }
    

    And switching value

    onChanged: (bool? value) {
      if (_isSelected) {
        selectedAnswer[question] =
            listAnswer[index]["id"];
      } else {
        selectedAnswer
            .addAll({question: listAnswer[index]["id"]});
      }
      setState(() {});
    },
    

    Full widget.

    class TEL extends StatefulWidget {
      const TEL({super.key});
    
      @override
      State<TEL> createState() => _TELState();
    }
    
    class _TELState extends State<TEL> {
      List<dynamic> survey = [
        {
          "id": 1,
          "question": "Question1",
          "answer": [
            {"id": 1, "name": "Option A"},
            {"id": 2, "name": "Option B"},
            {"id": 3, "name": "Option C"},
            {"id": 4, "name": "Option D"}
          ],
        },
        {
          "id": 2,
          "question": "Question2",
          "answer": [
            {"id": 1, "name": "Option A"},
            {"id": 2, "name": "Option B"},
            {"id": 3, "name": "Option C"},
            {"id": 4, "name": "Option D"}
          ],
        },
      ];
    
      Map<String, int> selectedAnswer = {};
    
      bool isSelected(String qustion, int answerID) {
        if (selectedAnswer.containsKey(qustion) &&
            selectedAnswer[qustion] == answerID) {
          return true;
        }
        return false;
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: ListView.builder(
            shrinkWrap: true,
            padding: const EdgeInsets.all(8),
            itemCount: survey.length,
            itemBuilder: (BuildContext context, int index) {
              var number = index + 1;
    
              final question = survey[index]["question"];
    
              List<Map> listAnswer = survey[index]["answer"];
    
              return Container(
                padding: EdgeInsets.all(10),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    SizedBox(
                      width: MediaQuery.of(context).size.width * 0.9,
                      child: Text(
                        question,
                        maxLines: 5,
                        overflow: TextOverflow.ellipsis,
                      ),
                    ),
                    SizedBox(height: 10),
                    ListView.builder(
                      shrinkWrap: true,
                      itemCount: listAnswer.length,
                      itemBuilder: (BuildContext context, int index) {
                        final bool _isSelected =
                            isSelected(question, listAnswer[index]["id"]);
                        return Container(
                          margin: EdgeInsets.only(bottom: 10),
                          child: ListTile(
                            title: Text(listAnswer[index]["name"].toString()),
                            trailing: Checkbox(
                              checkColor: Colors.white,
                              value: _isSelected,
                              shape: CircleBorder(),
                              onChanged: (bool? value) {
                                if (_isSelected) {
                                  selectedAnswer[question] =
                                      listAnswer[index]["id"];
                                } else {
                                  selectedAnswer
                                      .addAll({question: listAnswer[index]["id"]});
                                }
                                setState(() {});
                              },
                            ),
                          ),
                        );
                      },
                    )
                  ],
                ),
              );
            },
          ),
        );
      }
    }