Remove StatefulWidget from dynamic List in Flutter

40 Views Asked by At

If you have your StatefulWidget as an item of ListView and you need to remove one item, for example from the middle. It won't work. It will remove widget from the list but on the screen last item would be removed. I found relatively simple solution with GlobalKey<ScaffoldState>. If anyone knows better approach feel free to post answer.

class ItemWidget extends StatefulWidget {

  ItemWidget({required Key key}) : super(key: key); // <-- Add this to constructor

  @override
  ItemWidgetState createState() {
    return ItemWidgetState();
  }
}

And where you have your ListView code looks like this. What you need to do it's just deactivate Widget that you want to remove.

class YourListViewWidget {
  List<ItemWidget> itemWidgets = List.empty(growable: true);
  List<GlobalKey<ScaffoldState>> itemWidgetsKeys = List.empty(growable: true);


  Widget build(BuildContext context) {
  ...
  child: ListView.builder(
              controller: _scrollController,
              itemCount: itemWidgets.length,
              itemBuilder: (context, count) {
                return itemWidgets[count];
              },
            )
   ...
   }

  void addItem() {
    setState(() {
      GlobalKey<ScaffoldState> key = GlobalKey();
      itemWidgetsKeys.add(key);
   
      itemWidgets.add(ItemWidget(key: key));
    });
  }

  void removeItem() {
    setState(() {
      int indexToRemove = 0; <-- Any index that present in Lists.

      GlobalKey<ScaffoldState> key = itemWidgetsKeys[indexToRemove];
      key.currentState?.deactivate(); // <-- This is a main solution to this problem
      itemWidgets.removeAt(indexToRemove);
      itemWidgetsKeys.remove(key);
    });
  }
}

I tried solutions from this post Remove dynamically a widget from a dynamically created list flutter but they are work with StatelessWidget only.

1

There are 1 best solutions below

0
On

enter image description here

I did the same approach like this https://stackoverflow.com/questions/65003981/remove-dynamically-a-widget-from-a-dynamically-created-list-flutter and it works fine.

I do not see from your code call of these function remove and add.

class MyListViewWidget extends StatefulWidget {
  @override
  _MyListViewWidgetState createState() => _MyListViewWidgetState();
}

class _MyListViewWidgetState extends State<MyListViewWidget> {
  List<GlobalKey<_ItemWidgetState>> itemWidgetsKeys = [];
  List<ItemWidget> itemWidgets = [];

  @override
  Widget build(BuildContext context) {
    return Column(children:[
       ElevatedButton(
          onPressed: addItem,
          child: Text('Add Item'),
        ),
      Expanded(child:ListView.builder(
      itemCount: itemWidgets.length,
      itemBuilder: (context, index) {
        return ItemWidget(
          key: itemWidgetsKeys[index],
          onRemove: () => removeItem(index),
        );
      },
    ))
    ]);
  }

  void addItem() {
    setState(() {
      GlobalKey<_ItemWidgetState> key = GlobalKey();
      itemWidgetsKeys.add(key);
      itemWidgets.add(ItemWidget(
        key: key,
        onRemove: () => removeItem(itemWidgets.length - 1),
      ));
    });
  }

  void removeItem(int indexToRemove) {
    setState(() {
      itemWidgetsKeys.removeAt(indexToRemove);
      itemWidgets.removeAt(indexToRemove);
    });
  }
}

class ItemWidget extends StatefulWidget {
  final Function? onRemove;
  final int index;

  ItemWidget({Key? key, this.onRemove, this.index = 0}) : super(key: key);

  @override
  _ItemWidgetState createState() => _ItemWidgetState();
}

class _ItemWidgetState extends State<ItemWidget> {
  @override
  Widget build(BuildContext context) {
    return ListTile(
      title: Text('Item ${widget.key.hashCode}'),
      trailing: IconButton(
        icon: Icon(Icons.delete),
        onPressed: () {

          if(widget.onRemove != null){
            widget.onRemove!();
          }
        },
      ),
    );
  }
}