White flickering on GridView

I have checkbox for selecting and deselecting photos. There is a visible flicker for each tap.

screenrecorder-Trimmed-20201001

_mediaList has the photo asset. mediaModel has the necessary methods to add and remove the path of selected and deselected photos respectively.

 Widget build(BuildContext context) {
    super.build(context);
    return GridView.builder(
      itemCount: _mediaList.length,
      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisCount: 3, mainAxisSpacing: 4.0, crossAxisSpacing: 4.0),
      itemBuilder: (BuildContext context, int index) {
        final saved = mediaModel.getMedia().contains(
            _mediaList[index].relativePath + '/' + _mediaList[index].title);
        return FutureBuilder(
            future: _mediaList[index].thumbDataWithSize(200, 200),
            builder: (BuildContext context, snapshot) => snapshot.hasData
                ? GridTile(
                    header: saved
                        ? Icon(Icons.check_circle, color: Colors.white,)
                        : Icon(Icons.check_circle_outline, color: Colors.white,),
                    child: GestureDetector(
                        child: Image.memory(
                          snapshot.data,
                          fit: BoxFit.cover,
                        ),
                        onTap: () => setState(() => saved
                            ? mediaModel.removeMedia(
                                _mediaList[index].relativePath +
                                    '/' +
                                    _mediaList[index].title)
                            : mediaModel.addMedia(
                                _mediaList[index].relativePath +
                                    '/' +
                                    _mediaList[index].title))),
                  )
                : Container());
      },
    );
  }

Thanks in advance !!!

I think the problem is the future builder, and you may be rebuilding the entire grid every time something changes. This has tremendous impact in performance and causes problems like the ones you are facing.

The white screen is because you are showing a Container() every time the FurureBuilder is called.

You should extract the futures out an call setState only when the value changes. An may consider using a Provider and separating every Tile in a StatelessWidget to get better performance.

If you have trouble with this let me know and I’ll try to write you some code. Right know I’m in the car an not able to do it ;p

1 Like

I tried changing the Container to blue color. Still white flickering is there. So, I don’t think it is because of returning Container().

I even tried changing the Container() to CircularProgressIndicator(). Progress indicator is displayed only the first time. It is not displayed while clicking on checkbox.

I’m facing this flickering issue whenever I use Image.Memory()

You can access the main screen code here and mediaModel here

@F.lucadetena I tried changing the future builder and use Provider. But couldn’t do it successfully :frowning_face:
Can you help me, doing it the right way?

1 Like

I think this is the cause of your issue. This value should be determined in your provider itself instead of calculating in your builder function. Because when you add it in builder, it’s rechecking for each item and re-rendering it.

Also I see that you have a _mediaList, why don’t you add a saved boolean in the in the class, similar to relativePath and just set this everytime you check/uncheck a card.

void setSaved(bool value, int index) {
    List<MediaModel> temp = _mediaModel;
   MediaModel item = temp[index];
    temp[index].saved = value;

if(value) {
  addMedia(item.relativePath + '/' + item.title)))
else {
  removeMedia(itemrelativePath + '/' + item.title)
}
    _mediaModel = temp;
    notifyListeners();
}

Something on these lines. Then you can modify your UI like this:

 Widget build(BuildContext context) {
    super.build(context);
    return GridView.builder(
      itemCount: _mediaList.length,
      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisCount: 3, mainAxisSpacing: 4.0, crossAxisSpacing: 4.0),
      itemBuilder: (BuildContext context, int index) {
        return FutureBuilder(
            future: _mediaList[index].thumbDataWithSize(200, 200),
            builder: (BuildContext context, snapshot) => snapshot.hasData
                ? GridTile(
                    header: _mediaList[index].saved
                        ? Icon(Icons.check_circle, color: Colors.white,)
                        : Icon(Icons.check_circle_outline, color: Colors.white,),
                    child: GestureDetector(
                        child: Image.memory(
                          snapshot.data,
                          fit: BoxFit.cover,
                        ),
                        onTap: () => mediaProvider.setSaved(!_mediaList[index].saved, index)),
                  )
                : Container());
      },
    );
  }

Hope this solves the problem.

3 Likes

That was exactly the problem.

1 Like