Search code examples
firebaseflutterflutter-providerflutter-futurebuilder

Flutter getting range error while trying to delete items inside futurebuilder with Dismissible ListView


I want to have a list of items from my firestore, which I want to display and the user can dismiss them. (Im doing this with FirebaseApi().getSwiperData(fooNotifier) which is giving me a copy of the data I want) If the list is empty I want to show a message.

When I'm trying to implement it without setstate im getting the following range error:

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

In my opinion there is no need for setstate since im working with a Consumer, but something doesnt work here and I really dont have an idea anymore.

Using setstate everything works fine, but I dont want the whole widget to rebuild.

My code:

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:
              }
            },
          );
        }),
      ],
    );

Solution

  • Im proud to tell you that I fixed the problem. Im still pretty new to flutter and I can imagine that this also could be a common mistake for rookies.

    As you can see in my code im working with the FutureBuilder which is basically nothing else than a ListView.Builder with async operations and State Management.

    So when I receive my data, I'm showing them to the users. Because I'm working with Consumers from the provider package which does listen to any state changes (Thats also why I dont need a SetState here) Im receiving any kind of changes.

    Now instead of removing my index with consumerValues.swiperList.removeAt(index); which doesnt' communicate my changes

    I created a function in my notifier class:

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

    and called the function instead, which does communicate my changes.

    consumerValues.removeSwipeItems(index);