Reputation: 874
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
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