okarpov
okarpov

Reputation: 874

Flutter - dynamic toggle buttons with dynamic state variables

I'm trying to create toggle buttons dynamically according to a set of data got from server. It requires me to create state select variables dynamically as well and thus they can not be used directly in onPressed event.

I use "catching variable" technic but toggle buttons does not change their state on clicking even they change their boolean state variables

Map<String, List<bool>> toggleButtonValues = new Map<String, List<bool>>();
List<Widget> toggleButtons = new List<Widget>();

  void init() {
    for (int i = 0; i < gl.allfeatures.length; i++) {
      List<Widget> rowcat = new List<Widget>();
      Text category =
          new Text("Select Options - " + gl.allfeatures[i]["category"]);
      rowcat.add(category);
      toggleButtons.add(new Row(children: rowcat));
      List<Widget> tbrow;
      for (int c = 0; c < gl.allfeatures[i]["features"].length; c++) {
        if (c % 2 == 0) {
          tbrow = new List<Widget>();
          toggleButtons.add(new Row(children: tbrow));
        }

        toggleButtonValues.addEntries([
          new MapEntry<String, List<bool>>(
              toggleButtonValues.length.toString(), new List<bool>())
        ]);
        toggleButtonValues.entries.last.value.add(true);
        var ltl=toggleButtonValues.entries.last;
        ToggleButtons tb = new ToggleButtons(
          children: [new Text(gl.allfeatures[i]["features"][c]["name"])], 
          isSelected: toggleButtonValues.entries.last.value,
          onPressed: (index)=>
          setState((){
            ltl.value[0]^=true;
          }
          ),);

        tbrow.add(tb);
      }
    }

  }

@override
  Widget build(BuildContext context) {
    return Scaffold(
        key: _context,
        appBar: CustomAppBar(),
        body: Container(
          margin: EdgeInsets.only(bottom: 82.0),
          child: SingleChildScrollView(
            padding: EdgeInsets.all(9.0),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: toggleButtons,
            ),
          ),
        ),
        floatingActionButton:
            Column(mainAxisAlignment: MainAxisAlignment.end, children: <Widget>[
          new Container(
            padding: EdgeInsets.all(0),
            height: 8,
            child: new Divider(
              height: 0.0,
              thickness: 2,
              color: Colors.grey,
            ),
            margin:
                EdgeInsets.only(right: 0.0, left: 0.0, top: 0.0, bottom: 5.0),
          ),
          Row(
            children: <Widget>[
              Expanded(
                flex: 1,
                child: Padding(
                  padding: EdgeInsets.only(left: 25),
                  child: Align(
                    alignment: Alignment.bottomLeft,
                    child: new FloatingActionButton.extended(
                        label: Text('Back'),
                        onPressed: () {
                          Navigator.pop(context);
                        },
                        heroTag: "btnBack"),
                  ),
                ),
              ),
              Expanded(
                flex: 1,
                child: Align(
                  alignment: Alignment.bottomRight,
                  child: new FloatingActionButton.extended(
                      label: Text('To Description'),
                      onPressed: () {
                        Navigator.pushNamed(context, "/cardescription");
                      },
                      heroTag: "btnDescription"),
                ),
              ),
            ],
          ),
        ]));
  }

Any suggestion on how to resolve this case?

UPDATE #1: DartPad example : https://dartpad.dev/a2800ad9c84c55e701bee17d0594c6d6

SOLUTION: my problem was in initialization lists in build method, should be separated and initialized in the initState method.

Upvotes: 0

Views: 2439

Answers (1)

Kahou
Kahou

Reputation: 3488

Generate ToggleButtons from data source.

  List<List<IconData>> source;
  List<List<bool>> values;

  Iterable<Widget> generateToggleButtons() sync* {
    for (var index = 0; index < source.length; index += 1) {
      final children = source[index].map((value) => Icon(value)).toList();
      final isSelected = values[index];

      yield ToggleButtons(
        children: children,
        isSelected: isSelected,
        onPressed: (index) {
          setState(() {
            isSelected[index] = !isSelected[index];
          });
        },
      );
    }
  }
    source = [
      [Icons.ac_unit, Icons.call, Icons.cake],
      [Icons.access_alarm, Icons.backspace, Icons.calendar_today],
      [Icons.dashboard, Icons.edit, Icons.face],
    ];

    values = List.generate(
      source.length,
      (index) => List.generate(source.length, (index) => true),
    );

Try it on DartPad

Upvotes: 2

Related Questions