0

i previously asked a question about widgets not being updated here: flutter slider not updating widget variables

i got a great answer which explained to me more about how states work and i experimented a little further and now have an issue where my widget inside a list is not being updated even though i update the state in a setstate.

The Widget in question not being updated is the TestBoxNumber widget in the testBoxList list after it has been added to the list. I realize that if i change the builder to return the widget itself rather than from the list it works, and i'm not sure why this is the case!

Once again any help would be greatly appreciated and i hope this helps someone facing the same issue as well :)

Main Page Code

class TestPage extends StatefulWidget {
  static const id = "test_page";

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

class _TestPageState extends State<TestPage> {
  List testBoxList = [];
  List testSlideList = [];
  List testParamList = [];

  void updateFunc(ind, newVal) {
    setState(() {
      testParamList[ind] = newVal;
    });
  }

  void addSlider() {
    setState(() {
      double slideValue = 0;
      testParamList.add(slideValue);
      int boxIndex = testParamList.length - 1;

      testBoxList.add(TestBoxNumber(
        numberDisplay: testParamList,
        boxIndex: boxIndex,
      ));
      testSlideList.add(TestSlider(
        testValue: testParamList,
        updateFunc: updateFunc,
        boxIndex: boxIndex,
      ));
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          addSlider();
        },
      ),
      body: Padding(
        padding: const EdgeInsets.all(30.0),
        child: ListView(
          children: [
            Text("Test Page"),
            // Builder for viewers
            ListView.builder(
              shrinkWrap: true,
              physics: ClampingScrollPhysics(),
              itemCount: testBoxList.length,
              itemBuilder: (BuildContext ctx, int index) {
                return testBoxList[index];
                // return Text(testParamList[index].toString());
                // return TestBoxNumber(
                //     numberDisplay: testParamList, boxIndex: index);
              },
            ),
            // Builder for sliders
            ListView.builder(
              shrinkWrap: true,
              physics: ClampingScrollPhysics(),
              itemCount: testSlideList.length,
              itemBuilder: (BuildContext ctx, int index) {
                return testSlideList[index];
              },
            ),
          ],
        ),
      ),
    );
  }
}

TestBoxNumber Widget

class TestBoxNumber extends StatelessWidget {
  final List numberDisplay;
  final int boxIndex;

  TestBoxNumber({required this.numberDisplay, required this.boxIndex});

  Widget build(BuildContext context) {
    return Text(this.numberDisplay[this.boxIndex].toString());
  }
}

Slider Widget

class TestSlider extends StatefulWidget {
  List testValue;
  dynamic updateFunc;
  int boxIndex;

  TestSlider({
    required this.testValue,
    required this.updateFunc,
    required this.boxIndex,
  });

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

class _TestSliderState extends State<TestSlider> {
  // double curValue = widget.testValue;

  @override
  Widget build(BuildContext context) {
    double curValue = widget.testValue[widget.boxIndex];

    return Slider(
      activeColor: themeData.primaryColorLight,
      value: curValue,
      min: 0,
      max: 100,
      divisions: 50,
      label: curValue.round().toString(),
      onChanged: (double value) {
        setState(() {
          curValue = value;
        });
        widget.updateFunc(widget.boxIndex, value);
      },
    );
  }
}

1 Answers1

1

Me again )

Ok, so what is wrong right now is that you are using widgets, stored in the list instead of creating ones again:

You should not do this:

ListView.builder(
              shrinkWrap: true,
              physics: ClampingScrollPhysics(),
              itemCount: testBoxList.length,
              itemBuilder: (BuildContext ctx, int index) {
                return testBoxList[index];
                // return Text(testParamList[index].toString());
                // return TestBoxNumber(
                //     numberDisplay: testParamList, boxIndex: index);
              },
            )

but return new TestBoxNumber widgets (you actually has it commented, not sure why you did that):

ListView.builder(
                  shrinkWrap: true,
                  physics: ClampingScrollPhysics(),
                  itemCount: testBoxList.length,
                  itemBuilder: (BuildContext ctx, int index) {
                    return TestBoxNumber(numberDisplay: testParamList, boxIndex: index);
                  },
                )

so you will render widgets from scratch instead of pulling it from memory (list) and causing some weird things. Flutter is pretty optimized for such re-rendering.

So summarizing all of above: just pass data into widgets in build method. Do not store widgets in memory to reuse later.

UPD: also you can just pass double (let's call it yourDoubleValue) into TestBoxNumber instead of list and index. And then use Text('$yourDoubleValue');

obywan
  • 854
  • 8
  • 14
  • thanks again for responding and answering!! What i don't understand is why do widgets stored in a list not get updated as such like other variables? Adding to this, the Slider Widget seems to work fine in the second listview builder, so why does it not work the first? hahaha i actually commented it because i wanted to understand this particular way of storing widgets in lists and why it doesn't work – Isaac Marcus Lam May 21 '21 at 01:55
  • @IsaacMarcusLam I can't say for sure why exactly it's not working with storing widgets in a list (I can't explain in details what is happening internally in flutter framework). Maybe because Stateless widgets are meant to be immutable. This would explain why sliders work OK — they are Statefull. – obywan May 21 '21 at 08:05
  • alright, thanks for the help man! i did try making the widdget statefull but that did not help either so still not sure unfortunately haahaha – Isaac Marcus Lam May 25 '21 at 00:59