Delete Specific ListTile from ListView.builder with longPress

Issue

In ListView.builder I’m adding a new ListTile with the button Pressed.
Now when I press on ListTile I want to delete that widget.
I have tried to do that by wrapping the widget with InkWell but when I try to delete it deletes from the last ListTile.
How to delete that specific ListTile when I longPressed on that.

Below here is the code

import 'package:flutter/material.dart';

class Home extends StatefulWidget {
  const Home({Key? key}) : super(key: key);

  @override
  State<Home> createState() => _HomeState();
}

/*InkWell(
                  child: widgets[index],
                  onLongPress: () {
                    showDialog(
                        context: context,
                        builder: (context) => AlertDialog(
                              title: Text('Delete?'),
                              actions: [
                                IconButton(
                                    onPressed: () {
                                      widgets.removeAt(index);
                                      setState(() {
                                        Navigator.pop(context);
                                      });
                                    },
                                    icon: Icon(Icons.check))
                              ],
                            ));
                  },
                );*/

class _HomeState extends State<Home> {
  @override
  List<Widget> widgets = [];
  int inde = 0;
  List<List> blogList = [];

  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('Note'),
          centerTitle: true,
        ),
        body: Column(children: [
          Expanded(
            child: ListView.builder(
              itemCount: widgets.length,
              shrinkWrap: true,
              itemBuilder: (BuildContext context, int index) {
                return InkWell(
                  child: widgets[index],
                  onLongPress: () {
                    showDialog(
                        context: context,
                        builder: (context) => AlertDialog(
                              title: Text('Delete?'),
                              actions: [
                                IconButton(
                                    onPressed: () {
                                      widgets.removeAt(index);
                                      setState(() {
                                        Navigator.pop(context);
                                      });
                                    },
                                    icon: Icon(Icons.check))
                              ],
                            ));
                  },
                );
              },
            ),
          ),
          FloatingActionButton(
            onPressed: () {
              setState(() {
                widgets.add(Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Container(
                      width: 150,
                      decoration: BoxDecoration(
                        borderRadius: BorderRadius.circular(15),
                        border: Border.all(width: 2),
                        color: Color.fromARGB(255, 76, 178, 204),
                      ),
                      child: ListTile(
                        leading: Icon(Icons.circle),
                        title: TextField(),
                      )),
                ));
              });
            },
            child: Icon(Icons.add),
          ),
        ]));
  }
}

Solution

Actually your code works, it deletes the ListTile which you use long press on.

The problem is that you do not assign different controllers to the TextField widgets. So if you enter some text into them, and call setState when deleting one, the values in the TextFields will be wrong, and it looks like the last one is deleted.

So you need to add the following logic to your code:

  1. Create another list like widgets for the controllers.
  2. When adding a new item, create a new controller and assign it to the TextField.
  3. When deleting an item, dispose the controller and remove it from the controllers’ list.
  4. Don’t forget to dispose all remaining controllers when the widget is disposed.

Here is a sample code, check for the comments where I added to your code. You can run it on DartPad.

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: Scaffold(
        body: Center(
          child: Home(),
        ),
      ),
    );
  }
}

class Home extends StatefulWidget {
  const Home({Key? key}) : super(key: key);

  @override
  State<Home> createState() => _HomeState();
}

class _HomeState extends State<Home> {
  List<Widget> widgets = [];
  // this is the list for the controllers
  List<TextEditingController> controllers = [];
  int inde = 0;
  List<List> blogList = [];
  
  // you need to add this in order to dispose
  // the controllers when the widget is disposed
  @override
  void dispose() {
    for (var controller in controllers) {
      controller.dispose();
    }
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text('Note'),
          centerTitle: true,
        ),
        body: Column(children: [
          Expanded(
            child: ListView.builder(
              itemCount: widgets.length,
              shrinkWrap: true,
              itemBuilder: (BuildContext context, int index) {
                return InkWell(
                  child: widgets[index],
                  onLongPress: () {
                    showDialog(
                        context: context,
                        builder: (context) => AlertDialog(
                              title: const Text('Delete?'),
                              actions: [
                                IconButton(
                                    onPressed: () {
                                      setState(() {
                                        widgets.removeAt(index);
                                        // dispose the controller
                                        controllers[index].dispose();
                                        // remove the controller from list
                                        controllers.removeAt(index);                                          
                                      });
                                      Navigator.pop(context);
                                    },
                                    icon: const Icon(Icons.check))
                              ],
                            ));
                  },
                );
              },
            ),
          ),
          FloatingActionButton(
            onPressed: () {
              setState(() {
                // create a new controller and add it to the list
                final newController = TextEditingController();
                controllers.add(newController);
                
                widgets.add(Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Container(
                      width: 150,
                      decoration: BoxDecoration(
                        borderRadius: BorderRadius.circular(15),
                        border: Border.all(width: 2),
                        color: const Color.fromARGB(255, 76, 178, 204),
                      ),
                      child: ListTile(
                        leading: const Icon(Icons.circle),
                        // assign the controller to the field
                        title: TextField(controller: newController),
                      )),
                ));
              });
            },
            child: const Icon(Icons.add),
          ),
        ]));
  }
}

I suggest that following the convention, begin all private members of your state class with an underscore, so rename controllers to _controllers etc.

Answered By – Peter Koltai

Answer Checked By – Willingham (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *