Vineeth Mohan
Vineeth Mohan

Reputation: 2864

update checkbox and return value from dialog in flutter

I am trying to add some city list to a dialog with checkbox so that i need to implement multiple click on items. what I am trying to do is given below.

onPressed from button calls Rest Service and on success result I just show a dialog

void showCityDialog(BuildContext context) {
    SimpleDialog dialog = new SimpleDialog(
      title: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: <Widget>[
          new Text(
            "CITIES",
            style: TextStyle(fontSize: 18.0, color: Colors.black),
            textAlign: TextAlign.center,
          ),
          new RaisedButton(
            onPressed: () {print("clicked");},
            color: Color(0xFFfab82b),
            child: new Text(
              "Done",
              style: TextStyle(color: Colors.white),
            ),)],),
      children: <Widget>[
        Column(
          mainAxisAlignment: MainAxisAlignment.start,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            new Container(
              constraints: BoxConstraints(maxHeight: 500.0),
              child: ListView.builder(
                scrollDirection: Axis.vertical,
                itemCount: cityData.length,
                itemBuilder: (context, position) {
                  return new CheckboxListTile(
                    value: checkboxValueCity,
                    onChanged: (bool value) {
                      setState(() {
                        checkboxValueCity = value;
                      });
                    },
                    activeColor: Color(0xFFfab82b),
                    dense: true,
                    title: Text(
                      cityData[position].city_name,
                      style: TextStyle(fontSize: 16.0, color: Colors.black),
                    ),);},),),],)],);
    showDialog(
        context: context,
        builder: (BuildContext context) {
          return dialog;
        });
  }

checkboxValueCity is a boolean variable in class , on click of chekboxListItem i need to update checkbox value as checked and uncheced. At the same time need to add/remove that item to a list which is also inside that class.

But in my code checkbox is not refershing on every click but when i close that box and open it again checkbox is checked. then how can i get multiple click from tile and how can i return list from dialog?

Upvotes: 15

Views: 25831

Answers (4)

Muhammad Aamir
Muhammad Aamir

Reputation: 2676

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

enter image description here

Upvotes: 18

nat101
nat101

Reputation: 395

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.

Upvotes: 7

Duy Hoang
Duy Hoang

Reputation: 552

I modified your code a bit, I want when users check the list, the list won't be updated to the main view, but they will when users click the "Update" button. But some how, it doesn't work. Can you please check ? Thank you very much

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 = [];
  List<String> selectedCitiesTemp = [];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("App Bar"),
      ),
      body: Center(
        child: Column(
          children: <Widget>[
            _list(),
            RaisedButton(
              child: Text("Update From TMP List"),
              onPressed: () {
                setState(() {
                  selectedCities = selectedCitiesTemp;
                });
              },
            )
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
          child: Icon(Icons.add),
          onPressed: () {
            showDialog(
                context: context,
                builder: (BuildContext context) {
                  return _MyDialog(
                    cities: allCities,
                    selectedCities: selectedCities,
                    onSelectedCitiesListChanged: (cities) {
                      setState(() {
                        selectedCitiesTemp = cities;
                      });
                    },
                  );

                });
          }),
    );
  }
  Widget _list() {
    List<Widget> list = [];
    for(String item in selectedCities) {
      list.add(ListTile(
        title: Text(item),
      ));
    }
    return Column(
      children: list
    );
  }
}

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

Upvotes: 0

Albert Lardizabal
Albert Lardizabal

Reputation: 6846

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

Upvotes: 21

Related Questions