简体   繁体   中英

How to fix "A dismissed Dismissible widget is still part of the tree." error in flutter

I am building a fluter app with dismissible widget, firebase and StreamBuilder and getting following error "A dismissed Dismissible widget is still part of the tree."

Please find the below code sniped for the same.

Expanded(
                  child: StreamBuilder(
                    stream: Firestore.instance
                        .document('/users/User1/Trips/${widget.tripId}')
                        .collection('TropDocs')
                        .snapshots(),
                    builder: (context, snapshot) {
                      if (!snapshot.hasData) return const Text("Loading....");
                      return ListView.builder(
                        itemExtent: 150.0,
                        itemCount: snapshot.data.documents.length,
                        itemBuilder: (context, index) {

final item = snapshot.data.documents[index];
                          final itemID =
                              snapshot.data.documents[index].documentID;
                          final list = snapshot.data.documents;      
return Dismissible(
   key: Key(itemID),
              // We also need to provide a function that tells our app
              // what to do after an item has been swiped away.
              onDismissed: (direction) {
                // Remove the item from our data source.

                //fBtDoc.deleteTraveldoc(item);
                //Firestore.instance.collection('/users/User1/Trips/${widget.tripId}/TropDocs/').document('$itemID').delete();
                setState(() {
                  list.removeAt(index);
                });

                // Then show a snackbar!
                Scaffold.of(context)
                    .showSnackBar(SnackBar(content: Text("$item dismissed")));
              },
              // Show a red background as the item is swiped away
              background: Container(color: Colors.red),
              child: _buildlistitem(
                            context, snapshot.data.documents[index])
);

                        }
                      );
                    },
                  ),
                )

Probably, I'm late, but I think it will be helpful for others. Had the same problem and even setting

key: Key(itemId[index]),

didn't work. However,

key: UniqueKey(),

worked perfectly for me

I think that's because you are trying to use same key for every dismissible.

key: Key(itemID)

It should be key: Key(itemID[index])

In my cause, I have used as below

key: Key(index),

and then I did change it as below. It's working

key: UniqueKey(),

Remove setState block, streamBuilder will rebuild list by itself

 setState(() {
   list.removeAt(index);
 });

The reason is that the value passed to the key property isn't unique or related to the index of a list. The solution is quite simple and all you need to do is set the key property to UniqueKey(), like this:

key: UniqueKey(),

I would have done something like this to remove swiping from right to left

                        confirmDismiss: (direction) {
                      return Future.value(direction == DismissDirection.endToStart);
                    },
                    onDismissed: (direction) {
                      setState(() {
                        list.removeAt(index);
                      });
                    },

A workaround for a single widget dismissible is shown below and for the dismissible in a list write logic according to the code provided. Here we put an if condition for the Dismissible and in onDismissed just set that bool variable to false so that it will not remains in the widget tree.

if (_boolVariable)
 Dismissible(
    key: Key('anyString'),
    onDismissed: (direction) {
      //your code here
      setState(() => _boolVariable = false);
    },
  child: YourWidget())

将密钥更改为:

key: UniqueKey(),

try to change remove(index) function under onDismissed: like that;

 ***- mylist.removeAt(index);***

Because, remove function removes items. And yo dismissed nothing but looks dismissed and trows error : A dismissed Dismissible widget is still part of the tree.

***- so must be declared like this : mylist.remove(item);***

My problem

I have had a similar problem, but a little bit more complex. I wanted to use ReordableListView with ListTile 's along with Dismissible .

My code

Container(
  child: ReorderableListView.builder(
    onReorder: (int oldIndex, int newIndex) {},
    itemCount: _savedLocations.length,
    itemBuilder: (context, index) {
      LocationModel? locationItem = _savedLocations?[index];
        return Dismissible(
        // key: UniqueKey(),
        // key: Key('$index'),
        key: Key('${locationItem?.id}'),
        onDismissed: (direction) {
          LocationModel dismissed = _savedLocations[index];
          setState(() { _savedLocations.removeAt(index); });
          ScaffoldMessenger.of(context).showSnackBar(SnackBar(
          content: Text('Location: $dismissedValue dismissed')));
        },
        child: ListTile(
          // key: Key('$index'),
          // key: UniqueKey(),
          key: ValueKey('${locationItem?.id}'),
          title: Text(locationItem?.name ?? ''),
          subtitle: Text(locationItem?.country ?? ''),
        ),
    ),
),

Detailed explanation

I have started with ListTile and added key: Key('$index') , everything was working as expected. Then I wanted to add dismiss functionality so I wrapped it in Dismissible . Dismissible item also expect unique key, but I found out that actions on items with key: UniqueKey() assigned stopped working (dragging, dismissible).

Note: I have left commented out lines with wrong keys. For example: Key('$index') cannot be used for Dismissible because it will be deleted at the time of dismissal and causes error. I strongly suggest you to try it and see the error when trying to dismiss list item by swiping left or right.

Solution

Solution was to set Dismissible key to unique item Key('${locationItem?.id}') and ListTile key to ValueKey('${locationItem?.id}') . In this is case both Drag&drop (reordable) and dismissible funcionality work as expected.

Hope it helps

Reference: How to use ReorderableListView with DismissDirection in Flutter?

Why giving index as key not working

key: Key(index) : in this case the widget in widget tree will be bind in to the key which is the index, when you remove an item from the tree the build method will re-run and it looks for the widget with the key is there and always it can find the index there as the next element in the list will be replaced by the current item with "same index" that is why you are not getting this error when you try to remove it from end of the list the index can't be replaced because there is no element after this so instead of using index as key use something unique in that element like the id of element or UniqueKey()

key: Key(index) will throw error

use

key: Key(item.id), or key: UniqueKey(),

I'am also fall this error & debug with the following logic Instead of

key: Key(itemID),

use

key: Key(itemID[itemIDIndex]),

and in your setstae logic replace

setState(() {
              list.removeAt(index);
            });

with

setState(() {
              itemID.removeAt(itemIDIndex);
            });

this will solve the problem.

For reference see the Image Screenshot项目生成器 在此处删除索引

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM