Build a multi-select list with Flutter

JC.log
3 min readJun 1, 2021

Hey everyone, today we will build a simple app which will do the following things:

  1. Show a list of items
  2. Select/Deselect multiple items from the list
  3. Show check mark on selected items
  4. Show count of total items selected

This is a very simple project so we will not be using any fancy state management library. We will just use setState .

Let’s start by creating a project using flutter create multi-select

Now, let’s create our HomePage where we will show the list of items. HomePage widget will be a stateful widget because we will need setState to update the state of the screen.

Quick tip: If you are using VSCode, you can simply write “stful" in the editor to create a stateful widget quickly.

class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {@override
Widget build(BuildContext context) {
return Scaffold(
...
);
}
}

Now we will create a dummy class called Itemwhich will have two fields titleand price.

class Item {
String title;
int price;

Item(title, price){
this.title = title;
this.price = price;
}
}

As you can see, we are populating the fields using a constructor.

Next, we will create a widget which will show a specific Item.

We will pass three things to the widget.

  • Item data
  • isSelected — boolean (if true , we will show a checkmark in the corner)
  • onTap — Callback when widget is tapped
class ItemCard extends StatelessWidget {
final Function onTap;
final bool isSelected;
final Item item;
const ItemCard(
{@required this.onTap, @required this.isSelected, @required this.item});
@override
Widget build(BuildContext context) {
return TextButton(
style: TextButton.styleFrom(
elevation: 5,
backgroundColor: Colors.white,
),
onPressed: onTap,
child: Stack(
children: [
Align(
alignment: Alignment.center,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(item.title, style: TextStyle(fontSize: 20)),
SizedBox(height: 10),
Text('\$${item.price}')
],
),
),
if (isSelected) // Show tick mark only if item is selected
Align(
alignment: Alignment.topLeft,
child: Padding(
padding: const EdgeInsets.all(10),
child: Icon(Icons.check_circle, color: Colors.green),
),
),
],
),
);
}
}

This is how our single item will look in both states.

Left is unselected and right is selected

Okay, now left is to put all these pieces together.

I have used a GridView to show the list of items here. In the children of the GridView we will pass list of ItemCard.

On ItemCard tap we will do this — If Item exists in the selectedItems list, then we will remove it, Otherwise we will add it to the list.

class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<Item> items = [
Item('Item1', 200),
Item('Item2', 50),
...
];
List<Item> selectedItems = [];@override
Widget build(BuildContext context) {
return Scaffold(
body: GridView.count(
crossAxisCount: 2,
crossAxisSpacing: 10.0,
mainAxisSpacing: 10.0,
shrinkWrap: true,
children: List.generate(
items.length,
(index) {
return ItemCard(
onTap: () {
setState(() {
if (selectedItems.contains(items[index])) {
selectedItems.remove(items[index]);
} else {
selectedItems.add(items[index]);
}
});
},
item: items[index],
isSelected: selectedItems.contains(items[index]),
);
},
),
),
floatingActionButton: TextButton(
style: TextButton.styleFrom(
backgroundColor: Colors.blue,
),
onPressed: () {},
child: Text('${selectedItems.length} Items',
style: TextStyle(color: Colors.white)),
),
);
}
}

I have used List.generate to generate a list of widget from the items array. You can also use, items.map((item) => ItemCard()).toList() instead of that.

Here is the final output, after executing the code.

Final Output

This is a very simple implementation, but you can create better UI for the ItemCard and make it look eye-catching.

That’s it for this one. Hope you like it.

Thank you for reading until this point. Make sure to leave a comment for any suggestions and 👏 for this story.

--

--

JC.log

Just an average guy, showing average coding content.