繁体   English   中英

如何修复“已关闭的 Dismissible 小部件仍然是树的一部分。” flutter 错误

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

我正在构建一个带有 dismissible 小部件 firebase 和 StreamBuilder 的 flutter 应用程序,并收到以下错误“A dismissed Dismissible widget is still part of the tree.”

请找到以下相同的代码。

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])
);

                        }
                      );
                    },
                  ),
                )

可能,我迟到了,但我认为这对其他人会有所帮助。 有同样的问题,甚至设置

key: Key(itemId[index]),

没用。 然而,

key: UniqueKey(),

非常适合我

我认为那是因为您试图对每个可解雇的人使用相同的key

key: Key(itemID)

它应该是key: Key(itemID[index])

在我的事业中,我使用如下

key: Key(index),

然后我确实将其更改如下。 它正在工作

key: UniqueKey(),

移除 setState 块,streamBuilder 将自行重建列表

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

原因是传递给 key 属性的值不是唯一的或与列表的索引相关。 解决方案非常简单,您只需将 key 属性设置为 UniqueKey(),如下所示:

key: UniqueKey(),

我会做这样的事情来消除从右到左的滑动

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

下面显示了单个小部件可关闭的解决方法,以及根据提供的代码在列表写入逻辑中可关闭的解决方法。 在这里,我们为 Dismissible 设置了一个 if 条件,在onDismissed中,只需将该 bool 变量设置为 false,这样它就不会保留在小部件树中。

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

将密钥更改为:

key: UniqueKey(),

尝试更改 onDismissed 下的 remove(index) 函数:就像那样;

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

因为,删除功能会删除项目。 并且你什么都没解雇,只是看起来被解雇并引发错误:被解雇的 Dismissible 小部件仍然是树的一部分。

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

我的问题

我遇到过类似的问题,但有点复杂。 我想将ReordableListViewListTile的以及Dismissible一起使用。

我的代码

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 ?? ''),
        ),
    ),
),

详细解释

我从ListTile开始并添加了key: Key('$index') ,一切都按预期工作。 然后我想添加关闭功能,所以我将它包装在Dismissible中。 Dismissible item 也需要唯一键,但我发现对带有key: UniqueKey() assigned 的项目的操作停止工作(拖动,dismissible)。

注意:我已经用错误的键注释掉了行。 例如: Key('$index')不能用于Dismissible ,因为在dismissible的时候会被删除导致错误。 我强烈建议您尝试通过向左或向右滑动来关闭列表项时看到错误。

解决方案

解决方案是将Dismissible键设置为唯一项Key('${locationItem?.id}')并将ListTile键设置为ValueKey('${locationItem?.id}') 在这种情况下,拖放(可重新记录)和可关闭功能都按预期工作。

希望能帮助到你

参考: How to use ReorderableListView with DismissDirection in Flutter?

为什么给索引作为键不起作用

key: Key(index) :在这种情况下,小部件树中的小部件将绑定到作为索引的键,当您从树中删除一个项目时,构建方法将重新运行并查找带有key 在那里并且它总是可以在那里找到索引,因为列表中的下一个元素将被具有“相同索引”的当前项目替换,这就是为什么当您尝试从列表末尾删除它时没有收到此错误的原因无法替换索引,因为在此之后没有元素,所以不要使用索引作为键,而是使用该元素中唯一的东西,例如元素的 id 或UniqueKey()

key: Key(index)会抛出错误

采用

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

我也遇到了这个错误并使用以下逻辑进行调试而不是

key: Key(itemID),

利用

key: Key(itemID[itemIDIndex]),

在你的 setstae 逻辑中替换

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

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

这将解决问题。

参考图片截图项目生成器 在此处删除索引

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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