Flutter Select Item of List
This was originally published at ww.nstack.in
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 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 enables 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.
We need a variable to flag the selection status of the item. To keep the track of the list of item selection, we will use Map. The Map will store the unique id as key and boolean as the selection flag.
Adding Flag Variable for tracing selection Status
Now we need to track which item is selected and which is not. To store this we need some kind of variable. As we have a list of data so we also need a variable that can store the list of data.
We can use a list but using a map will be better and effective here. We can have user_id as the key to map and value as boolean. As the list item has an id and it’s unique so using a map is the best option here.
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.
There are two places where we can put the select all the items on the list. Either, we can put the checkbox button in-app bar for selecting all the items or we can use the floating action button.
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.
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
This is the final which has all the required things.
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.