Flutter Multi-select ChoiceChip
Hello Everyone
In this article, we will see how to use ChoiceChip
to accept multiple selections
Let’s get started
First things first
I will create a demo project and in the main.dart in build sections, I will create a RaisedButton
so whefirstn I click on the button a dialog will be popped showing options to select.
Center(
child: RaisedButton(
child: Text("Report"),
onPressed: () {
//Here we call the open dialog
},
),
),
Now onPressed
we need to call the Open Dialog
class _MyHomePageState extends State<MyHomePage> {
// This function will open the dialog
_showReportDialog() {
showDialog(
context: context,
builder: (BuildContext context) {
//Here we will build the content of the dialog
}
);
} @override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: RaisedButton(
child: Text("Report"),
onPressed: () => _showReportDialog(),
),
),
);
}
}
Now I will create a Widget to hold and return the ChoiceChip
Here is the widget which accepts a List<String>
so I can populate the Chips using it
Now our widget has a single Choice “Not Interested”
class MultiSelectChip extends StatefulWidget {
final List<String> reportList; MultiSelectChip(this.reportList); @override
_MultiSelectChipState createState() => _MultiSelectChipState();
}class _MultiSelectChipState extends State<MultiSelectChip> {
bool isSelected = false; @override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(8.0),
child: ChoiceChip(
label: Text("Not Interested"),
selected: isSelected,
onSelected: (selected) {
setState(() {
isSelected = selected;
});
},
),
);
}
}
Now in _showReportDialog
function we need to call Our widget.
List<String> reportList = [
"Not relevant",
"Illegal",
"Spam",
"Offensive",
"Uncivil"
]; _showReportDialog() {
showDialog(
context: context,
builder: (BuildContext context) {
//Here we will build the content of the dialog
return AlertDialog(
title: Text("Report Video"),
content: MultiSelectChip(reportList),
actions: <Widget>[
FlatButton(
child: Text("Report"),
onPressed: () => Navigator.of(context).pop(),
)
],
);
});
}
}
Now let's populate the chips based on the reportList Now our Widget will become this one
class MultiSelectChip extends StatefulWidget {
final List<String> reportList; MultiSelectChip(this.reportList); @override
_MultiSelectChipState createState() => _MultiSelectChipState();
}class _MultiSelectChipState extends State<MultiSelectChip> {
String selectedChoice = ""; // this function will build and return the choice list
_buildChoiceList() {
List<Widget> choices = List(); widget.reportList.forEach((item) {
choices.add(Container(
padding: const EdgeInsets.all(2.0),
child: ChoiceChip(
label: Text(item),
selected: selectedChoice == item,
onSelected: (selected) {
setState(() {
selectedChoice = item;
});
},
),
));
}); return choices;
} @override
Widget build(BuildContext context) {
return Wrap(
children: _buildChoiceList(),
);
}
}
Now we have a single select chip in order to make it multi-select chip we need to save out selectedChoice
to a list, let's work it out.
Now to achieve this we use some methods available with the List
selectedChoices.contains(item)
selectedChoices.remove(item)
selectedChoices.add(item)
Now our _buildChoiceList
will look like below
// String selectedChoice = "";
List<String> selectedChoices = List();_buildChoiceList() {
List<Widget> choices = List(); widget.reportList.forEach((item) {
choices.add(Container(
padding: const EdgeInsets.all(2.0),
child: ChoiceChip(
label: Text(item),
selected: selectedChoices.contains(item),
onSelected: (selected) {
setState(() {
selectedChoices.contains(item)
? selectedChoices.remove(item)
: selectedChoices.add(item);
});
},
),
));
}); return choices;
}
The login we used here is if the list contains the item then we make it selected else unselected in the same way then a chip is selected if the List
already contains the item then we remove the existing one else we add the item into the List
selected: selectedChoices.contains(item),
and
setState(() {
selectedChoices.contains(item)
? selectedChoices.remove(item)
: selectedChoices.add(item);
});
Now the part is to pass the selected choices back we can achive this by passing a function which accepts a List<String>
in to our Widget
this how our code will be
In the content of our AlertDialog
in _showReportDialog
MultiSelectChip(
reportList,
onSelectionChanged: (selectedList) {
setState(() {
selectedReportList = selectedList;
});
},
),
Our MultiSelectChip
Will be like below
class MultiSelectChip extends StatefulWidget {
final List<String> reportList;
final Function(List<String>) onSelectionChanged; // +added MultiSelectChip(
this.reportList,
{this.onSelectionChanged} // +added
); @override
_MultiSelectChipState createState() => _MultiSelectChipState();
}class _MultiSelectChipState extends State<MultiSelectChip> {
// String selectedChoice = "";
List<String> selectedChoices = List(); _buildChoiceList() {
List<Widget> choices = List(); widget.reportList.forEach((item) {
choices.add(Container(
padding: const EdgeInsets.all(2.0),
child: ChoiceChip(
label: Text(item),
selected: selectedChoices.contains(item),
onSelected: (selected) {
setState(() {
selectedChoices.contains(item)
? selectedChoices.remove(item)
: selectedChoices.add(item);
widget.onSelectionChanged(selectedChoices); // +added
});
},
),
));
}); return choices;
} @override
Widget build(BuildContext context) {
return Wrap(
children: _buildChoiceList(),
);
}
}
Whenever our selection of chip changed we will trigger the onSelectionChanged
Our HomePageState build method will be as below
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
RaisedButton(
child: Text("Report"),
onPressed: () => _showReportDialog(),
),
Text(selectedReportList.join(" , ")),
],
),
),
);
}
So this is how can make a multi-select choice chip
To get all options available with ChoiceChip
check here
To get Full Source code check out my GitHub repo
Bonus
If you want to add the option to limit the number of selections refer the below gist code to get the code
Thanks for your time.
Hope you like it, if yes clap & share.