Save Multi Select Choice Chips selected/unselected state in an alert-dialog - flutter

I am filtering results in my application based off of the multichoice chips that are selected. I have it filtering results properly, however when I select the done button in the alert dialog it does not save the selected state of the choice chips. It also does not clear the selected states of the choice chips when I hit the clear button. Any recommendations?
MultiFilterChoiceChips Class:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
class MultiFilterChips extends StatefulWidget {
final List<String> filterList;
final Function(List<String>) onSelectionChanged;
MultiFilterChips(this.filterList, {this.onSelectionChanged});
#override
_MultiFilterChipsState createState() => _MultiFilterChipsState();
}
class _MultiFilterChipsState extends State<MultiFilterChips> {
List<String> selectedFilters = List();
_buildFilterList() {
List<Widget> filters = List();
widget.filterList..forEach((item){
filters.add(Container(
padding: const EdgeInsets.all(2.0),
child: ChoiceChip(
label: Text('$item'),
selected: selectedFilters.contains(item),
onSelected: (selected) {
setState(() {
selectedFilters.contains(item)
? selectedFilters.remove(item)
: selectedFilters.add(item);
widget.onSelectionChanged(selectedFilters);
});
},
),
));
});
return filters;
}
#override
Widget build(BuildContext context) {
return Wrap(
children: _buildFilterList(),
);
}
}
Filter Pressed (App Bar Icon) Alert Dialog:
_filterPressed() {
return showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
scrollable: true,
title: Text('Filter Scouts'),
content: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('Rank:'),
_multiFilterRankChipState(),
Padding(padding: EdgeInsets.all(5)),
Text('Patrol:'),
_multiFilterPatrolChipState(),
],
)),
actions: <Widget>[
FlatButton(
child: Text("Clear"),
onPressed: () {
filter = ""; //ranks filter string to send to the sqlite database
pfilter = ""; //patrol filter string to send to the sqlite database
setState(() {
selectedRanks.clear(); //List<String> that holds the selected ranks
selectedPatrols.clear(); //List<String> that holds the selected patrols
//sends the query to the database and resets the future list builder state
// back to initial state without filters
_searchResults(searchText);
});
},
),
FlatButton(
child: Text("Done"),
onPressed: () {
Navigator.of(context).pop();
})
],
);
});
}
Rank MultiFilter Call:
_multiFilterRankChipState() {
return MultiFilterChips(ranks, onSelectionChanged: (selectedList) {
setState(() {
//selectedList = selectedRanks;
selectedRanks = selectedList;
debugPrint("SELECTED LIST ${selectedRanks.toString()}");
_RanksFilterSet();
});
});
}
For getting the list of Patrols I am getting the distinct list from the sqlite database as the list patrols change overtime thus using a future builder to get the list of strings:
Patrol MultiFilter Call:
_multiFilterPatrolChipState() {
return Container(
child: FutureBuilder<List<String>>(
future: patrols(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return MultiFilterChips(snapshot.data,
onSelectionChanged: (selectedList) {
setState(() {
selectedPatrols = selectedList;
_PatrolFilterSet();
});
});
}
return Container(
alignment: AlignmentDirectional.center,
child: new CircularProgressIndicator(
strokeWidth: 7,
));
},
),
);
}
Let me know if you need more code! Thanks!

You can store the selected items in a Map. In this sample, multi-select mode will start on long press of an item. Multi-select mode will stop when there's no selected items left.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
var selectMode = false;
Map<String, bool> listItemSelected = {
'List 1': false,
'List 2': false,
'List 3': false,
'List 4': false,
'List 5': false,
'List 6': false,
'List 7': false,
'List 8': false,
'List 9': false,
};
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: ListView(
children: listItemSelected.keys.map((key) {
return Card(
child: GestureDetector(
onTap: () {
// if multi-select mode is true, tap should select List item
if (selectMode && listItemSelected.containsValue(true)) {
debugPrint('onTap on $key');
setState(() {
listItemSelected[key] = !listItemSelected[key];
});
} else {
// Stop multi-select mode when there's no more selected List item
debugPrint('selectMode STOP');
selectMode = false;
}
},
// Start List multi-select mode on long press
onLongPress: () {
debugPrint('onLongPress on $key');
if (!selectMode) {
debugPrint('selectMode START');
selectMode = true;
}
setState(() {
listItemSelected[key] = !listItemSelected[key];
});
},
child: Container(
// Change List item color if selected
color: (listItemSelected[key])
? Colors.lightBlueAccent
: Colors.white,
padding: EdgeInsets.all(16.0),
child: Text(key),
),
),
);
}).toList(),
),
),
);
}
}
Demo

Related

Flutter - how to implement checkboxes with Bloc

I am trying to create a list with checkboxes with a Select All option at the top.
The current code works fine with the SelectAll/De-selectAll.
The problem is, even the individual checkboxes are working as a SelectAll checkbox. Meaning, any checkbox when selected/de-selected, selects/de-selects all other checkboxes.
HomePage:
import 'dart:convert';
import 'dart:io';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:http/http.dart' as http;
import 'package:boost/resources/toast_display.dart';
import 'package:flutter/material.dart';
import 'package:internet_connection_checker/internet_connection_checker.dart';
import '../models/meetings.dart';
import '../models/test.dart';
import '../resources/app_strings.dart';
import '../utils/accesss_token_manager.dart';
import '../utils/app_urls.dart';
import '../utils/constants.dart';
import '../utils/routes.dart';
import '../widgets/cubit/notification_cubit.dart';
class NewHomeScreen extends StatefulWidget {
const NewHomeScreen({Key? key}) : super(key: key);
#override
State<NewHomeScreen> createState() => _NewHomeScreenState();
}
class _NewHomeScreenState extends State<NewHomeScreen> {
Meeting meeting = Meeting();
List<WeeklyMeeting> weeklyMeetingsList = [];
bool isSelectAll = false;
bool isMeetingSelected = false;
final allowNotifications = NotificationSetting(title: 'Allow Notifications');
final notifications = [
NotificationSetting(title: 'Show Message'),
NotificationSetting(title: 'Show Group'),
NotificationSetting(title: 'Show Calling'),
];
#override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(
title: const Text('Test'),
),
body: ListView(
children: [
buildToggleCheckbox(allowNotifications),
const Divider(),
...notifications.map(buildSingleCheckbox).toList(),
],
),
);
Widget buildToggleCheckbox(NotificationSetting notification) => buildCheckbox(
notification: notification,
onClicked: () {
BlocProvider.of<NotificationSelectionCubit>(context)
.toggleAllowNotificationSelection();
});
Widget buildSingleCheckbox(NotificationSetting notification) => buildCheckbox(
notification: notification,
onClicked: () {
BlocProvider.of<NotificationSelectionCubit>(context)
.toggleIndividualNotificationSelection();
},
);
Widget buildCheckbox({
required NotificationSetting notification,
required VoidCallback onClicked,
}) {
return BlocBuilder<NotificationSelectionCubit, NotificationState>(
builder: (context, state) {
return ListTile(
onTap: onClicked,
/// stack is used only to give the checkboxes a radio button look, when a checkbox
is selected it will look like a checked radio button, and when de-selected, it will
look like an unselected radio button.
leading: Stack(children: [
Visibility(
visible: state.value,
child: Checkbox(
shape: const CircleBorder(),
value: !state.value,
onChanged: (val) {
onClicked();
}),
),
Visibility(
visible: !state.value,
child: IconButton(
onPressed: () {
onClicked();
},
icon: const Icon(Icons.radio_button_checked),
),
)
]),
title: Text(
notification.title,
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
);
},
);
}
}
NotificationSelectionCubit class
class NotificationSelectionCubit extends Cubit<NotificationState> {
NotificationSelectionCubit()
: super(NotificationState(value: false, allowNotification: false));
final allowNotifications = NotificationSetting(title: 'Allow Notifications');
final notifications = [
NotificationSetting(title: 'Show Message'),
NotificationSetting(title: 'Show Group'),
NotificationSetting(title: 'Show Calling'),
];
void toggleIndividualNotificationSelection() {
for (var notification in notifications) {
return emit(NotificationState(
value: !state.value, allowNotification: state.allowNotification));
}
}
void toggleAllowNotificationSelection() => emit(NotificationState(
value: state.allowNotification,
allowNotification: !state.allowNotification));
}
And
class NotificationState {
bool value;
bool allowNotification;
NotificationState({required this.value, required this.allowNotification});
}
You can do it like this:
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => CheckBoxCubit(),
child: MaterialApp(
home: Scaffold(
body: BlocBuilder<CheckBoxCubit, CheckBoxState>(
builder: (context, state) {
return Center(
child: ListView.builder(
itemCount: state.checkBoxes.length,
itemBuilder: (context, index) {
return CheckboxListTile(
title: Text(state.checkBoxes[index]['name']),
value: state.checkBoxes[index]['isChecked'],
onChanged: (newValue) => context.read<CheckBoxCubit>().toggleNotification(index, newValue),
);
},
),
);
},
),
),
),
);
}
}
State file is as follows:
class CheckBoxState {
List<Map> checkBoxes;
CheckBoxState({
required this.checkBoxes,
});
CheckBoxState copyWith({
final List<Map>? checkBoxes,
}) {
return CheckBoxState(
checkBoxes: checkBoxes ?? this.checkBoxes,
);
}
}
Cubit file is as follow:
class CheckBoxCubit extends Cubit<CheckBoxState> {
CheckBoxCubit()
: super(CheckBoxState(
checkBoxes: [
{
"name": "Foobball",
"isChecked": false,
},
{
"name": "Baseball",
"isChecked": false,
},
],
));
void toggleNotification(int index, bool? newValue) => emit(
state.copyWith(
checkBoxes: List.from(state.checkBoxes)..[index]['isChecked'] = newValue,
),
);
}

How to Display selected data to another page in flutter

Hi i am new to flutter i have used sample database to get data of 10 users. this data is displayed in list tile with leading item is checkbox (to select / deselect). Now i need help in displaying the selected data on to the other page once i press cart button in the appbar..
here's my main
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_application_http_get/example.dart';
import 'package:flutter_application_http_get/screen.dart';
import 'package:flutter_application_http_get/selected.dart';
import 'package:flutter_application_http_get/sunday_state.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Sunday(),
);
}
}
class Sunday extends StatefulWidget {
const Sunday({Key? key}) : super(key: key);
#override
_SundayState createState() => _SundayState();
}
API Called Here
class _SundayState extends State<Sunday> {
var users = [];
Future getUserData() async {
var res =
await http.get(Uri.https("jsonplaceholder.typicode.com", "users"));
var jsonData = jsonDecode(res.body) as List;
setState(() {
users = jsonData;
});
}
#override
void initState() {
super.initState();
getUserData();
}
final notification = [SundayCheckBoxState()];
late final post;
data from post if checked printed..
getCheckboxItems() {
users.forEach((post) {
if (post['checked'] == true) {
print(post);
}
});
}
here in when onpressed i need to display the checked data on to the other page
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("User Data"),
actions: [
IconButton(
onPressed: getCheckboxItems,
icon: Icon(Icons.shopping_cart))
],
),
body: Container(
child: Card(
margin: EdgeInsets.all(20.0),
child: ListView.builder(
itemCount: users.length,
itemBuilder: (context, i) {
final post = users[i];
return Card(
elevation: 5,
child: Padding(
padding: const EdgeInsets.all(12.0),
child: ListView(shrinkWrap: true, children: [
ListTile(
leading: Checkbox(
value: post['checked'] ?? false,
onChanged: (value) {
setState(() {
post['checked'] = value;
});
}),
title: Text("${post['id']}" + "${post['name']}"),
),
])
));
}),
),
),
);
}
You can try this logic it worked for me :
var _isSelectedCheckBoxArr = [];
var _addSelectedValueArr = [];
Checkbox(
value: _isSelectedCheckBoxArr[i],
materialTapTargetSize:
MaterialTapTargetSize
.shrinkWrap,
onChanged: (s) {
setState(() {
_isSelectedCheckBoxArr[i] =
!_isSelectedCheckBoxArr[i];
});
print(
"$_tag onChanged: (s): $s");
if (s) {
setState(() {
_addSelectedValueArr.add(
"${users[i]}");
});
} else if (!s) {
setState(() {
_addSelectedValueArr
.remove(
users[i]);
});
}
}),
Then on the click of cart button pass the _addSelectedValueArr array in the constructor of the screen you want to display.

How to Drag and drop inside expansion tile?

How to handle drag and drop list into another list?
How can I achieve this?
Thanks for the help!
I have tried with drag_and_drop_lists package, but I'm stuck in handle inside and outside item.
Full Example :
import 'package:drag_and_drop_lists/drag_and_drop_lists.dart';
import 'package:flutter/material.dart';
Future<void> main() async {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: ExpansionTileExample(),
);
}
}
class FolderData {
String name;
List<ListData> listData;
FolderData({this.name, this.listData});
}
class ListData {
String name;
ListData({this.name});
}
class ExpansionTileExample extends StatefulWidget {
ExpansionTileExample({Key key}) : super(key: key);
#override
_ListTileExample createState() => _ListTileExample();
}
class _ListTileExample extends State<ExpansionTileExample> {
List<dynamic> _lists = [];
#override
void initState() {
super.initState();
_lists.add(FolderData(name: "Folder1", listData: []));
_lists.add(FolderData(name: "Folder2", listData: []));
_lists.add(ListData(
name: "List1",
));
_lists.add(ListData(
name: "List2",
));
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Expansion Tiles with drag and drop'),
),
body: DragAndDropLists(
children: List.generate(_lists.length, (index) => _buildList(index)),
onItemReorder: _onItemReorder,
onListReorder: _onListReorder,
listGhost: Padding(
padding: const EdgeInsets.symmetric(vertical: 30.0),
child: Center(
child: Container(
padding: EdgeInsets.symmetric(vertical: 30.0, horizontal: 100.0),
decoration: BoxDecoration(
border: Border.all(),
borderRadius: BorderRadius.circular(7.0),
),
child: Icon(Icons.add_box),
),
),
),
),
);
}
_buildList(int outerIndex) {
var innerList = _lists[outerIndex];
return (innerList is FolderData)
? DragAndDropListExpansion(
title: Text('List ${innerList.name}'),
subtitle: Text('Subtitle ${innerList.name}'),
leading: Icon(Icons.ac_unit),
children: List.generate(innerList.listData.length, (index) => _buildItem(innerList.listData[index].name)),
listKey: ObjectKey(innerList),
)
: DragAndDropList(
children: <DragAndDropItem>[
DragAndDropItem(
child: ListTile(title: Text(innerList.name)),
),
],
);
}
_buildItem(String item) {
return DragAndDropItem(
child: ListTile(
title: Text(item),
),
);
}
// ======== Stuck here ========
_onItemReorder(int oldItemIndex, int oldListIndex, int newItemIndex, int newListIndex) {
setState(() {
var movedDataOuter = _lists[oldListIndex];
if (movedDataOuter is ListData) {
// 1. drag list inside folder.
var movedItem = _lists.removeAt(oldListIndex);
_lists[newListIndex].listData.insert(newItemIndex, movedItem);
} else {
// 2. remove list from folder.
var movedItem = _lists[oldListIndex].listData.removeAt(oldItemIndex);
_lists.insert(newListIndex, movedItem);
// 3. drag & drop inner list inside folder
// var movedItem = _lists[oldListIndex].listData.removeAt(oldItemIndex);
// _lists[oldListIndex].listData.insert(newItemIndex, movedItem);
}
// 4. drag and drop list outsie folder
// var movedItem = _lists.removeAt(oldListIndex);
// _lists.insert(newListIndex, movedItem);
});
}
_onListReorder(int oldListIndex, int newListIndex) {
setState(() {
var movedList = _lists.removeAt(oldListIndex);
if (movedList is FolderData) {
_lists.insert(newListIndex, movedList);
} else {
_lists[newListIndex].listData.insert(newListIndex, movedList);
}
});
}
}
you can use following package on pub.dev : drag_and_drop_lists
package: link
and if you need a tutorial then link

How can I implement AlertDialog box inside ListView in Flutter Android app automatically without pressing any button?

I am working on a project where I have created a RestApi where I have data of cars and which I keep updating every 3 sec. The cars are at a junction of 4 roads, now when a car is approaching towards a particular road denoted by id the "is_green" will become true and in the ListView -> the CircleAvtar will become green which will indicate that car is comming or not Now My Question is
how can I implement a AlertDialog box which will popup automically whithout pressing any button when bool isGreen = userData[index]["is_green"] will contain value true . I am new to flutter so I don't know how to do that... Please help me out
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:async';
import 'dart:convert';
void main() {
runApp(MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData.dark(),
home: Home(),
));
}
class Home extends StatefulWidget {
Home({Key key}) : super(key: key);
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
Map data;
List userData;
Future getData() async {
print("updating data...");
http.Response response = await http.get("http://10.100.101.154:3000/xd");
data = jsonDecode(response.body);
setState(() {
userData = data["data"];
});
}
#override
void initState() {
super.initState();
Timer.periodic(new Duration(seconds: 3), (timer) {
getData();
});
}
Color getColor(bool isGreen) {
if (isGreen == true) {
return Colors.green;
} else {
return Colors.red;
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('SGH'),
centerTitle: true,
),
body: ListView.builder(
itemCount: userData == null ? 0 : userData.length,
itemBuilder: (BuildContext context, int index) {
bool isGreen = userData[index]["is_green"];
return Card(
child: Row(
children: <Widget>[
Padding(
padding: EdgeInsets.all(10),
child: CircleAvatar(
backgroundColor: getColor(isGreen),
minRadius: 6,
),
),
Padding(
padding: EdgeInsets.all(10),
child: Wrap(
direction: Axis.horizontal,
children: <Widget>[
Text(
"Road Id = ${userData[index]["id"]} \CarInQueue = ${userData[index]["car_que"]} \nIsGreen ? --> ${userData[index]["is_green"]} ",
style: TextStyle(
fontSize: 20, fontWeight: FontWeight.bold),
),
],
),
),
],
),
);
}),
);
}
}
Just check any time you update list of cars... Then show a Dialog with informations about which car is crossing
Future getData() async {
print("updating data...");
http.Response response = await http.get("http://10.100.101.154:3000/xd");
data = jsonDecode(response.body);
setState(() {
userData = data["data"];
});
checkDialog();
}
checkDialog(){
var item = userData.where((car)=>car["is_green"]).first;//this is the first car where is_green is true
if(item!=null){
showDialog(context:context,
builder:(BuildContext context)=>AlertDialog(
//.... content here
));
}
}

Is there an equivalent widget in flutter to the "select multiple" element in HTML

I am searching for a widget in flutter that is equal to
<select multiple=""></select>
in flutter.
An example implementation (for the web) is MaterializeCSS Select Multiple
As seen above I should be able to provide a list of items (with some of them preselected) and at the end retrieve a list of selected items or a map or something else.
An example implementation or a link to a documentation is very appreciated.
I don't think that a widget like that currently exists in Flutter, but you can build one yourself.
On mobile phones with limited screen space it would probably make sense to display a dialog with a submit button, like this native Android dialog.
Here is a rough sketch how to implement such a dialog in less than 100 lines of code:
class MultiSelectDialogItem<V> {
const MultiSelectDialogItem(this.value, this.label);
final V value;
final String label;
}
class MultiSelectDialog<V> extends StatefulWidget {
MultiSelectDialog({Key key, this.items, this.initialSelectedValues}) : super(key: key);
final List<MultiSelectDialogItem<V>> items;
final Set<V> initialSelectedValues;
#override
State<StatefulWidget> createState() => _MultiSelectDialogState<V>();
}
class _MultiSelectDialogState<V> extends State<MultiSelectDialog<V>> {
final _selectedValues = Set<V>();
void initState() {
super.initState();
if (widget.initialSelectedValues != null) {
_selectedValues.addAll(widget.initialSelectedValues);
}
}
void _onItemCheckedChange(V itemValue, bool checked) {
setState(() {
if (checked) {
_selectedValues.add(itemValue);
} else {
_selectedValues.remove(itemValue);
}
});
}
void _onCancelTap() {
Navigator.pop(context);
}
void _onSubmitTap() {
Navigator.pop(context, _selectedValues);
}
#override
Widget build(BuildContext context) {
return AlertDialog(
title: Text('Select animals'),
contentPadding: EdgeInsets.only(top: 12.0),
content: SingleChildScrollView(
child: ListTileTheme(
contentPadding: EdgeInsets.fromLTRB(14.0, 0.0, 24.0, 0.0),
child: ListBody(
children: widget.items.map(_buildItem).toList(),
),
),
),
actions: <Widget>[
FlatButton(
child: Text('CANCEL'),
onPressed: _onCancelTap,
),
FlatButton(
child: Text('OK'),
onPressed: _onSubmitTap,
)
],
);
}
Widget _buildItem(MultiSelectDialogItem<V> item) {
final checked = _selectedValues.contains(item.value);
return CheckboxListTile(
value: checked,
title: Text(item.label),
controlAffinity: ListTileControlAffinity.leading,
onChanged: (checked) => _onItemCheckedChange(item.value, checked),
);
}
}
You can use it like this:
void _showMultiSelect(BuildContext context) async {
final items = <MultiSelectDialogItem<int>>[
MultiSelectDialogItem(1, 'Dog'),
MultiSelectDialogItem(2, 'Cat'),
MultiSelectDialogItem(3, 'Mouse'),
];
final selectedValues = await showDialog<Set<int>>(
context: context,
builder: (BuildContext context) {
return MultiSelectDialog(
items: items,
initialSelectedValues: [1, 3].toSet(),
);
},
);
print(selectedValues);
}
Is this what you want?
In case you need a short and ready to use code, follow this article
import 'package:flutter/material.dart';
import 'package:multiple_selection_dialogue_app/widgets/multi_select_dialog.dart';
/// A demo page that displays an [ElevatedButton]
class DemoPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
/// Stores the selected flavours
List<String> flavours = [];
return ElevatedButton(
child: Text('Flavours'),
onPressed: () async {
flavours = await showDialog<List<String>>(
context: context,
builder: (_) => MultiSelectDialog(
question: Text('Select Your Flavours'),
answers: [
'Chocolate',
'Caramel',
'Vanilla',
'Peanut Butter'
])) ??
[];
print(flavours);
// Logic to save selected flavours in the database
});
}
}
import 'package:flutter/material.dart';
/// A Custom Dialog that displays a single question & list of answers.
class MultiSelectDialog extends StatelessWidget {
/// List to display the answer.
final List<String> answers;
/// Widget to display the question.
final Widget question;
/// List to hold the selected answer
/// i.e. ['a'] or ['a','b'] or ['a','b','c'] etc.
final List<String> selectedItems = [];
/// Map that holds selected option with a boolean value
/// i.e. { 'a' : false}.
static Map<String, bool> mappedItem;
MultiSelectDialog({this.answers, this.question});
/// Function that converts the list answer to a map.
Map<String, bool> initMap() {
return mappedItem = Map.fromIterable(answers,
key: (k) => k.toString(),
value: (v) {
if (v != true && v != false)
return false;
else
return v as bool;
});
}
#override
Widget build(BuildContext context) {
if (mappedItem == null) {
initMap();
}
return SimpleDialog(
title: question,
children: [
...mappedItem.keys.map((String key) {
return StatefulBuilder(
builder: (_, StateSetter setState) => CheckboxListTile(
title: Text(key), // Displays the option
value: mappedItem[key], // Displays checked or unchecked value
controlAffinity: ListTileControlAffinity.platform,
onChanged: (value) => setState(() => mappedItem[key] = value)),
);
}).toList(),
Align(
alignment: Alignment.center,
child: ElevatedButton(
style: ButtonStyle(visualDensity: VisualDensity.comfortable),
child: Text('Submit'),
onPressed: () {
// Clear the list
selectedItems.clear();
// Traverse each map entry
mappedItem.forEach((key, value) {
if (value == true) {
selectedItems.add(key);
}
});
// Close the Dialog & return selectedItems
Navigator.pop(context, selectedItems);
}))
],
);
}
}
import 'package:flutter/material.dart';
import 'package:multiple_selection_dialogue_app/pages/demo_page.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: DemoPage(),
),
),
);
}
}