0

I'm trying to create a simpler contextual action bar(CAB) https://pub.dev/packages/contextualactionbar

What I want to do is to update all the items in a ListView in Flutter. For example, I want to display a trailing checkbox for each ListTile when I long press on an item. The item can be a stateful widget.

Here is a gif of what I want to do:

Long press on items makes checkbox appear in Flutter

I tried to use a GlobalKey example from https://stackoverflow.com/a/57310380/5712419

Using a GlobalKey, only the visible items would update.

Update 28/04/2021: I answered this question with something that worked for me: the Provider package. I think it is cleaner than using a GlobalKey.

kyu
  • 111
  • 1
  • 10
  • You should not reference your list items by global key. Your state object should be in your statefull widget - the one that bulids the list. List elements should reference your state object. Your onLongPressCode will then manipulate your state object (List or however you decide to do it), and ListView will just rebuild using the state. – Andrija Mar 18 '21 at 11:33
  • If I understand correctly I have to get the state object ListObjectWidgetState from ListObjectWidget. How can I do that? https://pastebin.com/D79UYh6e – kyu Mar 18 '21 at 14:13
  • A problem I'm currently facing is that the selected items reset to unselected every time I scroll down the list. *(I think Flutter rebuilds these items on scroll)* – kyu Mar 19 '21 at 13:58
  • I have another problem: how to display the count of items from the list view. I really would like to have something like `_ListViewObjects(list).getWidgets()` – kyu Mar 19 '21 at 16:17
  • Can you share more code - that way I or someone lese could try to figure out what the problem is? – Andrija Mar 21 '21 at 04:56
  • 1
    It looks like you are doing it in the wrong way. For example - to display the item count, it looks like you are trying to reference UI components, and then count the number of widgets it produced. This is not how it should be done: Flutter is 'reactive' framework, and you should always draw your interface based on the data only; not based on other components. So if you wanted to display the number of items in the list, you just use: Text("Item count is ${ListObjects.length}"); This would run in build method of the Widget that holds your ListObjects. Don't derive it from other UI components. – Andrija Mar 21 '21 at 05:09
  • Your comment has really helped me! Thank you! – kyu Mar 22 '21 at 13:20

1 Answers1

0

It's possible to select all items in a ListView by using Provider. https://pub.dev/packages/provider

These are the steps I took.

Step 1: Create a class that extends ChangeNotifier for a single item

class SelectableItemState extends ChangeNotifier {
    
  bool _selectable = false;

  bool get selectable => _selectable;

  set selectable(bool value) {
    _selectable = value;
    notifyListeners();
  }
}

Step 2: Register the Change Notifier

return MultiProvider(
  providers: [
    ChangeNotifierProvider(create: (context) => SelectableItemState()),
  ], //...

Step 3: Create the Consumer, and update the state from the gesture detector

 return Consumer<SelectableItemState>(builder: (context, state, child) {
      return GestureDetector(){
           onLongPress: () {
             state.selectable = true;
           },
           child: Material( // use state.selectable in the item widget...

      }
 
 }

Step 4: Update the trailing of your item (if selectable, show checkbox, else, show an empty container)

trailing: (state.selectable)
    ? Checkbox(
        value: // state.selectedItem,
        onChanged: (value) {
          setState(() {
            // Here we can use something like
            // state.setSelectedItem(item, value);
          });
        },
      )
    : Container(),
kyu
  • 111
  • 1
  • 10