Can't update ListView inside showModalBottomSheet after delete from db

Viewed 885

I have a ModalBottomSheet and I have a ListView inside it. ListView is connected to a sqlite db. All create,read and delete methods are working fine but when I delete an item, I get the toast message which approves the operation but my view does not get updated. When I close the sheet and open again It's updated. My ModalBottomSheet codes are :

void popUpScreen(context) {
    showModalBottomSheet(
        context: context,
        builder: (BuildContext context) {
          return Container(
              color: Colors.blue[600],
              height: MediaQuery.of(context).size.height * .8,
              child: ListView.builder(
                  itemCount: _loclist.length,
                  itemBuilder: (context, index) {
                    return Padding(
                        padding: EdgeInsets.only(top: 8, left: 16, right: 16),
                        child: Card(
                          child: ListTile(
                            leading: Text(_loclist[index].name),
                            title: IconButton(
                              icon: Icon(Icons.delete),
                              onPressed: () async {
                                var result = await locationdbservice
                                    .deleteLocation(_loclist[index].id);
                                this._loclist.removeAt(index);
                                if (result > 0) {
                                  Toast.show("Silindi", context,
                                      duration: Toast.LENGTH_SHORT,
                                      gravity: Toast.BOTTOM);
                                  getLocations();
                                }
                              },
                            ),
                          ),
                        ));
                  }));
        });
  }

and getLocations() :

getLocations() async {
    _loclist = List<Loc>();
    var locations = await locationdbservice.readLocations();
    locations.forEach((location) {
      setState(() {
        var locationModel = Loc();
        locationModel.lat = location['lat'];
        locationModel.lon = location['lon'];
        locationModel.name = location['name'];
        locationModel.note = location['note'];
        locationModel.id = location['id'];
        _loclist.add(locationModel);
      });
    });
  }

I tried to write an initState() function which returns getLocations() and called it at the end of onPressed() with initState() but didn't work. I tried to make an empty initState() but didn't work. How can I update my ListView while I view it?

Edit: Here's where I call popUpScreen:

Widget locationsButton(BuildContext context) {
    return Container(
        width: 250,
        height: 60,
        child: ElevatedButton(
          style: ElevatedButton.styleFrom(
            padding: EdgeInsets.zero,
            shape:
                RoundedRectangleBorder(borderRadius: BorderRadius.circular(30)),
          ),
          clipBehavior: Clip.antiAlias,
          onPressed: () {
            popUpScreen(context);
          },
          child: Ink(
            decoration: BoxDecoration(
                gradient: LinearGradient(
                    begin: Alignment.bottomCenter,
                    end: Alignment.topCenter,
                    colors: [Colors.white70, Colors.white38])),
            child: Container(
              constraints: BoxConstraints(maxHeight: 300, minWidth: 50),
              alignment: Alignment.center,
              child: Text(
                "KONUMLARIM",
                style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
              ),
            ),
          ),
        ));
  }
3 Answers

Here I come with the solution. It happens always with showModelBottomSheet that it doesn't rebuild or change its state so I come across the solution. Add StatefulBuilder in ModelBottomSheet which will change its state onPressed Function. Also, your code is throwing exceptions so I handled these exceptions. Go to GitHub merge pull request and continue.

Thumbs up if this solution helped

Here is the sample code. I had implemented this just go to GitHub and start coding

  void popUpScreen() {
    showModalBottomSheet(
        context: context,
        builder: (BuildContext context) {
          return StatefulBuilder(
              builder: (BuildContext context, StateSetter mystate) {
            return Container(
                color: Colors.blue[600],
                height: MediaQuery.of(context).size.height * .8,
                child: ListView.builder(
                    itemCount: _loclist.length,
                    itemBuilder: (context, index) {
                      return Padding(
                          padding: EdgeInsets.only(top: 8, left: 16, right: 16),
                          child: Card(
                            child: ListTile(
                              leading: Text(_loclist[index].name),
                              title: IconButton(
                                icon: Icon(Icons.delete),
                                onPressed: () async {
                                  var result = await locationdbservice
                                      .deleteLocation(_loclist[index].id);
                                  mystate(() {
                                    this._loclist.removeAt(index);
                                  });
                                  if (result > 0) {
                                    Toast.show("Silindi", context,
                                        duration: Toast.LENGTH_SHORT,
                                        gravity: Toast.BOTTOM);
                                    getLocations();
                                  }
                                  setState(() {});
                                },
                              ),
                            ),
                          ));
                    }));
          });
        });
  }

Please check with setstate method

void popUpScreen(context) {
    showModalBottomSheet(
        context: context,
        builder: (BuildContext context) {
          return Container(
              color: Colors.blue[600],
              height: MediaQuery.of(context).size.height * .8,
              child: ListView.builder(
                  itemCount: _loclist.length,
                  itemBuilder: (context, index) {
                    return Padding(
                        padding: EdgeInsets.only(top: 8, left: 16, right: 16),
                        child: Card(
                          child: ListTile(
                            leading: Text(_loclist[index].name),
                            title: IconButton(
                              icon: Icon(Icons.delete),
                              onPressed: () async {
                                var result = await locationdbservice
                                    .deleteLocation(_loclist[index].id);
                                setState(() {
                                   this._loclist.removeAt(index); 
                              });
                                
                                if (result > 0) {
                                  Toast.show("Silindi", context,
                                      duration: Toast.LENGTH_SHORT,
                                      gravity: Toast.BOTTOM);
                                  getLocations();
                                }
                              },
                            ),
                          ),
                        ));
                  }));
        });
  }

According to the docs:

Calling setState notifies the framework that the internal state of this object has changed in a way that might impact the user interface in this subtree, which causes the framework to schedule a build for this State object.

So if the state of the widget changes you have to call setState((){}); to trigger a rebuild of the view and see immediately the changes implied by the new state.

Related