Sometimes we want to select more than one item of the list and perform some action i.e delete the selected item etc
I want to make this article production-ready so that developers can just copy and paste the code to their final project or to their client’s project.
Get Started
First of all, we need some data to make the app look like the real app and take some real scenarios. Create a data.dart
file and paste the code from this this link.
The code will look similar to the given snippet. I didn’t add the complete code in this article because that will take lots of lines and will unnecessarily make the article longer.
// https://raw.githubusercontent.com/nstack-in/flutter-select-list-item/master/lib/data.dart
class MyData {
static List<Map> data = [
{
"id": 1,
"name": "Marchelle",
"email": "mailward0@hibu.com",
"address": "57 Bowman Drive"
},
{
"id": 2,
"name": "Modesty",
"email": "mviveash1@sohu.com",
"address": "2171 Welch Avenue"
},
{
"id": 3,
"name": "Maure",
"email": "mdonaghy2@dell.com",
"address": "4623 Chinook Circle"
},
{
"id": 4,
"name": "Myrtie",
"email": "mkilfoyle3@yahoo.co.jp",
"address": "406 Kings Road"
},
{
"id": 5,
"name": "Winfred",
"email": "wvenn4@baidu.com",
"address": "2444 Pawling Lane"
}
];
}
Now you go the data and it’s time to render the data in the app and move towards the selection feature.
Building UI
Now we will make the UI using the ListView.builder. The data will be loaded from data.dart.
I am not going to use the network for loading the data because I assume you know how to do that and want to know about the selection feature only.
import 'package:flutter/material.dart';
import 'package:flutter_select_all_list/data.dart';
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
List<Map> staticData = MyData.data;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Select Item'),
),
body: ListView.builder(
itemBuilder: (builder, index) {
Map data = staticData[index];
return ListTile(
title: Text("${data['name']}"),
subtitle: Text("${data['email']}"),
leading: CircleAvatar(
child: Text('${data['id']}'),
),
);
},
itemCount: staticData.length,
),
);
}
}
Selection Mode
How do you see the selection mode in most of the app?
If I talk about myself then probably, I will say using a long press. i.e When you long press on the list item then it selects the long pressed item and enable the selection mode.
We will be building a similar thing in our app too.
If any item is selected from the list then the selection model is enabled.
Selection Mode | Action | Description |
---|---|---|
Disabled | tap on item | This will open the detail page |
Disable | long press on item | This will select the current item |
Enabled | tap on item | Select the tapped item |
Enabled | long press on item | Select the long-press item |
Adding Flag Variable for tracing selection Status
import 'package:flutter/material.dart';
import 'package:flutter_select_all_list/data.dart';
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
List<Map> staticData = MyData.data;
Map<int, bool> selectedFlag = {};
bool isSelectionMode = false;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Select Item'),
),
body: ListView.builder(
itemBuilder: (builder, index) {
Map data = staticData[index];
// For the first time selectedFlag[index] will be null
// so, for that time we will initialize with false
selectedFlag[index] = selectedFlag[index] ?? false;
bool isSelected = selectedFlag[index];
return ListTile(
onLongPress: () => onLongPress(isSelected, index),
onTap: () => onTap(isSelected, index),
title: Text("${data['name']}"),
subtitle: Text("${data['email']}"),
leading: _buildSelectIcon(isSelected, data), // updated
);
},
itemCount: staticData.length,
),
);
}
void onLongPress(bool isSelected, int index) {
setState(() {
selectedFlag[index] = !isSelected;
// If there will be any true in the selectionFlag then
// selection Mode will be true
isSelectionMode = selectedFlag.containsValue(true);
});
}
Widget _buildSelectIcon(bool isSelected, Map data) {
if (isSelectionMode) {
return Icon(
isSelected ? Icons.check_box : Icons.check_box_outline_blank,
color: Theme.of(context).primaryColor,
);
} else {
return CircleAvatar(
child: Text('${data['id']}'),
);
}
}
void onTap(bool isSelected, int index) {
if (isSelectionMode) {
setState(() {
selectedFlag[index] = !isSelected;
isSelectionMode = selectedFlag.containsValue(true);
});
} else {
// Open Detail Page
}
}
}
Adding Select All Button
Now we will add the select all button so that we can select all the items of the list using one tap/click. This is very important in the production app and this feature makes life easier when there is a very long list.
Add this line of code to the Scaffold
floatingActionButton: _buildSelectAllButton(),
The button will be visible when the selectionMode is enabled. The floating Button icon button changed based on the item selected.
Selection | Icon |
---|---|
no item selected | No Button |
Some item selected | check all icon |
all item selected | remove check icon |
Widget _buildSelectAllButton() {
// The button will be visible when the selectionMode is enabled.
if (isSelectionMode) {
bool isFalseAvailable = selectedFlag.containsValue(false); // check if all item is not selected
return FloatingActionButton(
onPressed: _selectAll,
child: Icon(
isFalseAvailable ? Icons.done_all : Icons.remove_done,
),
);
} else {
return null;
}
}
void _selectAll() {
bool isFalseAvailable = selectedFlag.containsValue(false);
// If false will be available then it will select all the checkbox
// If there will be no false then it will de-select all
selectedFlag.updateAll((key, value) => isFalseAvailable);
setState(() {
isSelectionMode = selectedFlag.containsValue(true);
});
}
Final Code
import 'package:flutter/material.dart';
import 'package:flutter_select_all_list/data.dart';
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
bool isSelectionMode = false;
List<Map> staticData = MyData.data;
Map<int, bool> selectedFlag = {};
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Select Item'),
),
body: ListView.builder(
itemBuilder: (builder, index) {
Map data = staticData[index];
selectedFlag[index] = selectedFlag[index] ?? false;
bool isSelected = selectedFlag[index];
return ListTile(
onLongPress: () => onLongPress(isSelected, index),
onTap: () => onTap(isSelected, index),
title: Text("${data['name']}"),
subtitle: Text("${data['email']}"),
leading: _buildSelectIcon(isSelected, data),
);
},
itemCount: staticData.length,
),
floatingActionButton: _buildSelectAllButton(),
);
}
void onTap(bool isSelected, int index) {
if (isSelectionMode) {
setState(() {
selectedFlag[index] = !isSelected;
isSelectionMode = selectedFlag.containsValue(true);
});
} else {
// Open Detail Page
}
}
void onLongPress(bool isSelected, int index) {
setState(() {
selectedFlag[index] = !isSelected;
isSelectionMode = selectedFlag.containsValue(true);
});
}
Widget _buildSelectIcon(bool isSelected, Map data) {
if (isSelectionMode) {
return Icon(
isSelected ? Icons.check_box : Icons.check_box_outline_blank,
color: Theme.of(context).primaryColor,
);
} else {
return CircleAvatar(
child: Text('${data['id']}'),
);
}
}
Widget _buildSelectAllButton() {
bool isFalseAvailable = selectedFlag.containsValue(false);
if (isSelectionMode) {
return FloatingActionButton(
onPressed: _selectAll,
child: Icon(
isFalseAvailable ? Icons.done_all : Icons.remove_done,
),
);
} else {
return null;
}
}
void _selectAll() {
bool isFalseAvailable = selectedFlag.containsValue(false);
// If false will be available then it will select all the checkbox
// If there will be no false then it will de-select all
selectedFlag.updateAll((key, value) => isFalseAvailable);
setState(() {
isSelectionMode = selectedFlag.containsValue(true);
});
}
}
Conclusion
I hope this article is helpful to you and you learn at least two-three new things. I have used various things in this article that might be new for some of you.
- containsValue
- updateAll
These must be new for most of you because I know this because one day I read all the methods available on different data types. If you learned something new or want to suggest something then please let me know in the comment.
Share this article with your friends or tweet about this article if you love this.
Thank you