Search code examples
flutterflutter-listviewflutter-build

Flutter CheckboxListTile not responding to changes with stream builder


I am trying to use a CheckboxListTile in a stream builder and right now I have it showing up in my listView but when I tap it the value is not changing.

I originally had the bool inPack = false; before the widget build and that would respond but every item in the listView toggles at the same time which was not what I wanted. I then moved it into the builder where I now believe it should be but now nothing toggles...

    builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
      //widget build for completed call
      if (snapshot.hasData) {
        return ListView.builder(
            itemCount: snapshot.data!.docs.length,
            itemBuilder: (context, index) {
              DocumentSnapshot doc = snapshot.data!.docs[index];
              bool inPack = false;
              return Padding(
                padding: const EdgeInsets.all(4.0),
                child: Card(
                  child: CheckboxListTile(
                    value: inPack,
                    onChanged: (inPack) {
                      setState(
                        () {
                          if (inPack == true) {
                            inPack = false;
                          } else {
                            inPack = true;
                          }
                        },
                      );
                    },

Solution

  • you define inPack inside stream builder so every time you call setState it define again. Put bool inPack = false out of stream builder. you should define it out of build so every time you call setState, it not getting define again.

    class _MyHomePageState extends State<MyHomePage> {
      
      bool inPack = false // define it here
      @override
      Widget build(BuildContext context) {
        
        return MaterialApp(
            ...
        );
      }
    }
    

    and if you have list of checkbox you have to provide list of check box value, like this:

    class _MyHomePageState extends State<MyHomePage> {
          
          List<bool> checkboxValues = List<bool>.generate(10, (index) => false); 
          @override
          Widget build(BuildContext context) {
            
            return StatefulBuilder(builder: (context, innerState) {
          return ListView.builder(
            itemCount: 10,
            itemBuilder: (context, index) {
              return Padding(
                padding: const EdgeInsets.all(4.0),
                child: Card(
                  child: CheckboxListTile(
                      value: checkboxValues[index],
                      onChanged: (value) {
                        innerState(
                     () {
                       checkboxValues[index] = value!;
                    },
                  );
                      }),
                ),
              );
            },
          );
        });
          }
        }
    

    and final tip, wrap your list view with StatefulBuilder so every time you call setState, it not update all your expensive widget like stream builder. just remember that if you are using StatefulBuilder, you should use innerState instead of setState to refresh state.