update checkbox and return value from dialog in flutter
Your dialog needs to be a StatefulWidget
(Flutter Github issue). The member variable that tracks selection state needs to be in the dialog class. You can use a callback to update a member variable in your parent class with the List
of selected cities. There also seem to be some issues using a ListView.builder
inside of a SimpleDialog
or AlertDialog
(search the Flutter Github for issues) so I used a plain Dialog
.
import 'package:flutter/material.dart';void main() => runApp(MyApp());class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Checkbox Dialog Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyHomePage(title: 'Flutter Checkbox Dialog Demo'), ); }}class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; @override _MyHomePageState createState() => _MyHomePageState();}class _MyHomePageState extends State<MyHomePage> { bool checkboxValueCity = false; List<String> allCities = ['Alpha', 'Beta', 'Gamma']; List<String> selectedCities = []; @override Widget build(BuildContext context) { return Scaffold( floatingActionButton: FloatingActionButton( child: Icon(Icons.add), onPressed: () { showDialog( context: context, builder: (context) { return _MyDialog( cities: allCities, selectedCities: selectedCities, onSelectedCitiesListChanged: (cities) { selectedCities = cities; print(selectedCities); }); }); }), ); }}class _MyDialog extends StatefulWidget { _MyDialog({ this.cities, this.selectedCities, this.onSelectedCitiesListChanged, }); final List<String> cities; final List<String> selectedCities; final ValueChanged<List<String>> onSelectedCitiesListChanged; @override _MyDialogState createState() => _MyDialogState();}class _MyDialogState extends State<_MyDialog> { List<String> _tempSelectedCities = []; @override void initState() { _tempSelectedCities = widget.selectedCities; super.initState(); } @override Widget build(BuildContext context) { return Dialog( child: Column( children: <Widget>[ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: <Widget>[ Text( 'CITIES', style: TextStyle(fontSize: 18.0, color: Colors.black), textAlign: TextAlign.center, ), RaisedButton( onPressed: () { Navigator.pop(context); }, color: Color(0xFFfab82b), child: Text( 'Done', style: TextStyle(color: Colors.white), ), ), ], ), Expanded( child: ListView.builder( itemCount: widget.cities.length, itemBuilder: (BuildContext context, int index) { final cityName = widget.cities[index]; return Container( child: CheckboxListTile( title: Text(cityName), value: _tempSelectedCities.contains(cityName), onChanged: (bool value) { if (value) { if (!_tempSelectedCities.contains(cityName)) { setState(() { _tempSelectedCities.add(cityName); }); } } else { if (_tempSelectedCities.contains(cityName)) { setState(() { _tempSelectedCities.removeWhere( (String city) => city == cityName); }); } } widget .onSelectedCitiesListChanged(_tempSelectedCities); }), ); }), ), ], ), ); }}
Use StatefulBuilder
to update Widgets only inside Dialog. StatefulBuilder
is best for update sebsection of the widget tree where state is needed.
simple code snippet
void _showDialog() { showDialog( context: context, builder: (context) { return StatefulBuilder( // StatefulBuilder builder: (context, setState) { return AlertDialog( actions: <Widget>[ Container( width: 400, child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ Text( "Student Attendence", style: TextStyle(fontSize: 20), ), SizedBox( height: 5, ), Container( height: 2, color: Colors.black, ), SizedBox( height: 15, ), CheckboxListTile( value: user1, title: Text("user1"), onChanged: (value){ setState(() { user1=value; }); }, ), Divider( height: 10, ), CheckboxListTile( value: user2, title: Text("user2"), onChanged: (value){ setState(() { user2=value; }); }, ), Divider( height: 10, ), CheckboxListTile( value: user3, title: Text("user3"), onChanged: (value){ setState(() { user3=value; }); }, ), Divider( height: 10, ), CheckboxListTile( value: user4, title: Text("user4"), onChanged: (value){ setState(() { user4=value; }); }, ), Divider( height: 10, ), SizedBox( height: 5, ), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[ Material( elevation: 5.0, color: Colors.blue[900], child: MaterialButton( padding: EdgeInsets.fromLTRB( 10.0, 5.0, 10.0, 5.0), onPressed: () {}, child: Text("Save", textAlign: TextAlign.center, style: TextStyle( color: Colors.white, fontSize: 15, )), ), ), Material( elevation: 5.0, color: Colors.blue[900], child: MaterialButton( padding: EdgeInsets.fromLTRB( 10.0, 5.0, 10.0, 5.0), onPressed: () { setState(() { Navigator.of(context).pop(); }); }, child: Text("Cancel", textAlign: TextAlign.center, style: TextStyle( color: Colors.white, fontSize: 15, )), ), ), Material( elevation: 5.0, color: Colors.blue[900], child: MaterialButton( padding: EdgeInsets.fromLTRB( 10.0, 5.0, 10.0, 5.0), onPressed: () {}, child: Text("Select All", textAlign: TextAlign.center, style: TextStyle( color: Colors.white, fontSize: 15, )), ), ), ], ) ], )) ], ); }, ); }, ); }
example
Although Albert's answer works, you need not go thru all that. Simply wrap the content: with a StatefulBuilder, voila!https://api.flutter.dev/flutter/widgets/StatefulBuilder-class.html.
Note: It is important where you declare the variable(s) you want to change.