cover image
Nitish Kumar Singh
Nitish Kumar Singh
Clock Image 9 minutes
Posted on
December 27, 2020

Flutter Select Item of List


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.

data.dart
// 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 #

Screenshot of final 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.

home.dart
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 ModeActionDescription
Disabledtap on itemThis will open the detail page
Disablelong press on itemThis will select the current item
Enabledtap on itemSelect the tapped item
Enabledlong press on itemSelect the long-press item

Adding Flag Variable for tracing selection Status #

home.dart
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
    }
  }

}

Looking for Flutter Developer

Hire Now

Adding Select All Button #

Screenshot of final UI

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.

SelectionIcon
no item selectedNo Button
Some item selectedcheck all icon
all item selectedremove 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 #

home.dart
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.

Github Repo

Thank you

Last updated at Sunday, Dec 27, 2020 by Nitish Kumar Singh
comments powered by Disqus

Subscribe to our Newsletter


Tweet this article