Flutter 在尝试使用 Dismissible ListView 删除 futurebuilder 中的项目时出现范围错误

Posted

技术标签:

【中文标题】Flutter 在尝试使用 Dismissible ListView 删除 futurebuilder 中的项目时出现范围错误【英文标题】:Flutter getting range error while trying to delete items inside futurebuilder with Dismissible ListView 【发布时间】:2021-05-30 23:40:36 【问题描述】:

我想要一个来自我的 firestore 的项目列表,我想要显示它并且用户可以关闭它们。 (我使用 FirebaseApi().getSwiperData(fooNotifier) 执行此操作,这给了我想要的数据的副本)如果列表为空,我想显示一条消息。

当我尝试在没有setstate 的情况下实现它时,我收到以下范围错误:

════════ Exception caught by widgets library ═══════════════════════════════════
The following RangeError was thrown building:
RangeError (index): Invalid value: Not in inclusive range 0..2: 3

在我看来,不需要setstate,因为我正在使用Consumer,但是这里有些东西不起作用,我真的没有任何想法了。

使用setstate 一切正常,但我不想重建整个小部件。

我的代码:

class _SwipeScreenState extends State<SwipeScreen> 
  Future fooFuture;

  @override
  void initState() 
    // TODO: implement initState
    super.initState();
    final fooNotifier = Provider.of<FooNotifier>(context, listen: false);
    fooFuture = FirebaseApi().getSwiperData(fooNotifier);
  

  @override
  Widget build(BuildContext context) 
    print('rebuild swipescreen');
    return Stack(
      children: [
        Consumer<FooNotifier>(builder: (__, consumerValues, _) 
          return FutureBuilder(
            future: fooFuture,
            // ignore: missing_return
            builder: (context, snapshot) 
              switch (snapshot.connectionState) 
                case ConnectionState.none:
                  break;
                case ConnectionState.waiting:
                  return Center(child: CircularProgressIndicator());
                  break;
                case ConnectionState.done:
                  return consumerValues.swiperList.length != 0
                      ? ListView.builder(
                          physics: NeverScrollableScrollPhysics(),
                          itemCount: consumerValues.swiperList.length ?? 0,
                          itemBuilder: (BuildContext context, int index) 
                             return Dismissible(
                              resizeDuration: Duration(milliseconds: 1500),
                              onDismissed: (DismissDirection direction) 
                                //setState(() 
                                  //Doesnt work here like expected
                                  consumerValues.swiperList.removeAt(index);
                                  print(consumerValues.swiperList);
                              // );
                              ,

                              secondaryBackground: Container(
                                child: Center(
                                  child: Text(
                                    'geliked',
                                    style: TextStyle(color: Colors.black),
                                  ),
                                ),
                                color: Colors.lightGreenAccent,
                              ),
                              background: Container(
                                  child: Center(
                                    child: Text(
                                      'Nicht interessant',
                                      style: TextStyle(color: Colors.black),
                                    ),
                                  ),
                                  color: Colors.redAccent),
                              child: SwipeCard(
                                cardWidth: MediaQuery.of(context).size.width * 1,
                                cardHeight:
                                    MediaQuery.of(context).size.height * 1,
                                foo2Name:
                                    consumerValues.swiperList[index].foo2Name,
                                fooName:
                                    consumerValues.swiperList[index].fooName,
                                imageUrl:
                                    consumerValues.swiperList[index].imageUrl,
                              ),
                              key: UniqueKey(),
                              direction: DismissDirection.horizontal,
                            );
                          ,
                        )
                      : SwipeNoItems(); // Showing up if the list is empty

                  break;
                default:
              
            ,
          );
        ),
      ],
    );

【问题讨论】:

【参考方案1】:

我很自豪地告诉你,我解决了这个问题。我对 Flutter 还是很陌生,我可以想象这对于新手来说也可能是一个常见的错误。

正如您在我的代码中看到的那样,我正在使用 FutureBuilder,这基本上就是带有异步操作和状态管理的 ListView.Builder

所以当我收到我的数据时,我会将它们展示给用户。因为我正在使用提供程序包中的Consumers,它确实会监听任何状态更改(这也是我在这里不需要SetState 的原因)我收到任何类型的更改。

现在不再使用 consumerValues.swiperList.removeAt(index); 删除我的索引 这不会传达我的更改

我在通知程序类中创建了一个函数:

void removeSwipeItems(idx)
    _swiperList.removeAt(idx);
    notifyListeners();
  

并改为调用函数which does communicate my changes

consumerValues.removeSwipeItems(index);

【讨论】:

以上是关于Flutter 在尝试使用 Dismissible ListView 删除 futurebuilder 中的项目时出现范围错误的主要内容,如果未能解决你的问题,请参考以下文章

使用 Flutter/Dart 关闭 Dismissible

Flutter Dismissible 未从树中移除

Flutter:Dismissible 小部件内的 SnackBar 无法正常工作

flutter Dismissible 可以在拖动时隐藏的widget

Dismissible confirmDismiss 结合新的路由导航导致 Flutter 崩溃

被解雇的 Dismissible 小部件仍然是颤动树的一部分