Hey everyone, today we will build a simple app which will do the following things:
- Show a list of items
- Select/Deselect multiple items from the list
- Show check mark on selected items
- 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 Item
which will have two fields title
and 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
dataisSelected
— boolean (iftrue
, 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.
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.
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.