How to select multiple items in ListView | Flutter

Aakash Pamnani
5 min readApr 4, 2024

--

Have you ever marveled at the functionality of the Gmail app’s list view, where you can effortlessly select multiple emails? This multi-selection feature enhances user experience, enabling efficient management of emails. In Flutter, replicating such functionality is not only possible but also relatively straightforward. In this tutorial, we’ll explore how to implement multi-selection in a ListView widget, like the Gmail app, using Flutter.

Implementing Multi-Selection in ListView

We’ll begin by designing a Flutter widget that mirrors the behavior of the Gmail app’s multi-selection ListView. Here’s how we can achieve this:


import 'package:flutter/material.dart';

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MultiSelectListView(),
);
}
}

class MultiSelectListView extends StatefulWidget {
@override
_MultiSelectListViewState createState() => _MultiSelectListViewState();
}

class _MultiSelectListViewState extends State<MultiSelectListView> {
List<String> emails = List.generate(20, (index) => "Email $index");
Set<int> selectedIndexes = {};

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Multi-Selection ListView (Gmail Style)'),
actions: [
IconButton(
icon: Icon(Icons.delete),
onPressed: () {
setState(() {
emails.removeWhere(
(email) => selectedIndexes.contains(emails.indexOf(email)));
selectedIndexes.clear();
});
},
),
],
),
body: ListView.builder(
itemCount: emails.length,
itemBuilder: (context, index) {
final email = emails[index];
return ListTile(
title: Text(email),
onTap: () {
setState(() {
if (selectedIndexes.contains(index)) {
selectedIndexes.remove(index);
} else {
selectedIndexes.add(index);
}
});
},
selected: selectedIndexes.contains(index),
selectedTileColor: Colors.blue.withOpacity(0.5),
);
},
),
);
}
}

Explanation

  • We’ve created a stateful widget MultiSelectListView, which holds a list of emails and the selected indexes.
  • The app bar contains an action button (IconButton) to delete selected emails.
  • The ListView.builder widget is used to create a scrollable list of emails dynamically.
  • Each email is represented by a ListTile, capable of handling tap events and displaying the email
  • Tapping an email toggles its selection state. The setState method is called to update the UI
  • Selected emails are visually highlighted using the selectedTileColor property.

Adding Animation Like Gmail

One of the subtle yet effective user interface elements in applications like Gmail is the animation that accompanies item selection. In Gmail, when you select an email, the profile photo of the sender often transitions into a checkmark icon, indicating the selection. This animation not only provides visual feedback to the user but also enhances the overall user experience.

In Flutter, achieving such animations is straightforward, thanks to the framework’s built-in animation capabilities. We can utilize Flutter’s animation widgets and controllers to create smooth transitions between different states of UI elements. Let’s integrate a similar animation into our multiple selection ListView to mimic the behavior seen in the Gmail app.

Below is the modified code with added animation:

import 'package:flutter/material.dart';

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: SelectionListView(),
);
}
}

class SelectionListView extends StatefulWidget {
@override
_SelectionListViewState createState() => _SelectionListViewState();
}

class _SelectionListViewState extends State<SelectionListView>
with SingleTickerProviderStateMixin {
List<String> emails = List.generate(20, (index) => "Email $index");
Set<int> selectedIndexes = {};
late AnimationController _controller;
late Animation<double> _animation;
int? currentSelectedIndex;

@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: Duration(milliseconds: 300),
);
_animation = Tween<double>(begin: 0.0, end: 1.0).animate(_controller);
}

@override
void dispose() {
_controller.dispose();
super.dispose();
}

void _startAnimation() {
_controller.reset();
_controller.forward();
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Gmail-like Multiple Selection ListView'),
actions: [
IconButton(
icon: Icon(Icons.delete),
onPressed: () {
// Perform action on selected items
print('Deleting selected emails: $selectedIndexes');
},
),
],
),
body: ListView.builder(
itemCount: emails.length,
itemBuilder: (context, index) {
return GestureDetector(
onTap: () {
setState(() {
if (selectedIndexes.contains(index)) {
selectedIndexes.remove(index);
currentSelectedIndex = null; // Reset current selected index
} else {
selectedIndexes.add(index);
currentSelectedIndex = index; // Update current selected index
}
});
_startAnimation();
},
child: ListTile(
title: Text(emails[index]),
leading: AnimatedBuilder(
animation: _animation,
builder: (context, child) {
return CircleAvatar(
child: currentSelectedIndex == index
? Transform(
alignment: Alignment.center,
transform: Matrix4.identity()
..rotateY(3.14)
..rotateY(_animation.value * 3.14),
child: Icon(
Icons.check,
),
)
: selectedIndexes.contains(index)
? Icon(
Icons.check,
)
: Text("E"),
);
},
),
selected: selectedIndexes.contains(index),
selectedTileColor: Colors.blue.withOpacity(0.5),
),
);
},
),
);
}
}

Explanation

  • We’ve added an AnimationController _controller and an Animation _animation to manage the animation.
  • The _startAnimation() function is called whenever an item is tapped, triggering the animation.
  • Inside the ListTile, we use an AnimatedBuilder widget to animate the rotation of the checkmark icon.
  • The rotation animation is applied only to the selected items, giving the effect of the profile photo transitioning into a checkmark.

Conclusion

In this tutorial, we’ve explored how to implement multi-selection in a ListView widget using Flutter, inspired by the Gmail app’s functionality. This feature enhances user interaction, enabling more efficient management of lists within your Flutter applications. Feel free to customize the styling and functionality further to suit your app’s specific requirements. Happy coding!

I hope you found this article enjoyable! If you appreciated the information provided, you have the option to support me by Buying Me A Coffee! Your gesture would be greatly appreciated!

Follow Me

https://www.linkedin.com/in/aakashpamnani/

https://twitter.com/Aakash_P_

Thank you for taking the time to read this article. If you enjoyed it, feel free to explore more of my articles and consider following me for future updates. Your support is greatly appreciated!

--

--

Aakash Pamnani

Flutter, Java, developer. | Trying to explain concepts in the most straightforward way possible.