Home > other >  Flutter CheckboxListTile not responding to changes with stream builder
Flutter CheckboxListTile not responding to changes with stream builder

Time:08-28

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;
                          }
                        },
                      );
                    },

CodePudding user response:

You can create separate widget(context) to handle this.

class PackCheckBox extends StatefulWidget {
  final bool inPack;
  const PackCheckBox({Key? key, required this.inPack}) : super(key: key);

  @override
  State<PackCheckBox> createState() => _PackCheckBoxState();
}

class _PackCheckBoxState extends State<PackCheckBox> {
  late bool inPack = widget.inPack;
  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(4.0),
      child: Card(
        child: CheckboxListTile(
          value: inPack,
          onChanged: (value) {
            setState(
              () {
                inPack = !inPack;
              },
            );
          },
        ),
      ),
    );
  }
}

And use a stream variable ,instead of directly putting the method inside the stream. Also, when new stream will come data will change.

body: StreamBuilder<int>(
  stream: stream,
  builder: (context, snapshot) {
    if (!snapshot.hasData) return CircularProgressIndicator();
    bool inPack = snapshot.data?.isEven ?? false;
    return PackCheckBox(
      inPack: inPack,
    );
  },
),

CodePudding user response:

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.

  • Related