Shashi Kiran
Shashi Kiran

Reputation: 1079

Avoid rebuilding of children while scrolling in SliverGrid in flutter

Hi I am using the below code in a CustomScrollView to show images in grid using SliverGrid and SliverChildBuilderDelegate. On Scrolling very fast, the children widget that has already have cached image gets destroyed when gone off screen and rebuilt when they are on screen. How to avoid them destroying and rebuilding them on scroll?

    SliverGrid(
            gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
              maxCrossAxisExtent: 150,
              childAspectRatio: 1 / 1,
              crossAxisSpacing: 4.0,
              mainAxisSpacing: 4.0,
            ),
            delegate: SliverChildBuilderDelegate(
              (BuildContext context, int index) {
                return ClipRRect(
                    borderRadius: BorderRadius.circular(5.0),
                    child: Container(
                      alignment: Alignment.bottomRight,
                      padding: EdgeInsets.all(10.0),
                      decoration: BoxDecoration(
                        image: DecorationImage(
                          fit: BoxFit.fill,
                          image: CachedNetworkImageProvider(
                            "https://source.unsplash.com/${150}/${150 + index}/",
                          ),
                        ),
                      ),
                      child: index == (index / 2) + 1
                          ? Icon(
                              Icons.burst_mode,
                              color: AppTheme.fullWhite,
                            )
                          : index == (index / 6)
                              ? Icon(
                                  Icons.play_circle_filled,
                                  color: AppTheme.fullWhite,
                                )
                              : Container(),
                    ));
              },
              childCount: childCount,
            ),
          )

Note: if I remove the index in the image url, then on fast scroll it loads very quickly since its displaying the same image.

https://source.unsplash.com/${150}/${150 + index}/

Upvotes: 1

Views: 2383

Answers (3)

Danny
Danny

Reputation: 1

You can reset this global config

PaintingBinding.instance?.imageCache?.maximumSize = 5000;
PaintingBinding.instance?.imageCache?.maximumSizeBytes = 300 << 20;

Upvotes: 0

DIVYANSHU SAHU
DIVYANSHU SAHU

Reputation: 1215

Use the Wrapper Class Concept. This is a lengthy solution. But you can customize to your need to make it shorter.

    Widget decorationImage() {
        return DecorationImage(
            fit: BoxFit.fill,
            image: CachedNetworkImageProvider(
            "https://source.unsplash.com/${150}/${150 + index}/",
            );
    }

Wrapper class:

class CustomSliverGrid extends StatelessWidget {
  Widget _widget;
  CustomSliverGrid(this._widget);

  @override
  Widget build(BuildContext context) {
    return SliverGrid(
      gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
        maxCrossAxisExtent: 150,
        childAspectRatio: 1 / 1,
        crossAxisSpacing: 4.0,
        mainAxisSpacing: 4.0,
      ),
      delegate: SliverChildBuilderDelegate(
            (BuildContext context, int index) {
          return ClipRRect(
              borderRadius: BorderRadius.circular(5.0),
              child: Container(
                alignment: Alignment.bottomRight,
                padding: EdgeInsets.all(10.0),
                decoration: BoxDecoration(
                  image: _widget,
                ),
                child: index == (index / 2) + 1
                    ? Icon(
                  Icons.burst_mode,
                  color: AppTheme.fullWhite,
                )
                    : index == (index / 6)
                    ? Icon(
                  Icons.play_circle_filled,
                  color: AppTheme.fullWhite,
                )
                    : Container(),
              ));
        },
        childCount: childCount,
      ),
    );
  } 
}

Use that class in your code as:

class YourWidgetPlace extends StatelessWidget {

    Widget decorationImage() {
      return DecorationImage(
          fit: BoxFit.fill,
          image: CachedNetworkImageProvider(
          "https://source.unsplash.com/${150}/${150 + index}/",
      );
    } 
    
    @override
    Widget build(BuildContext context) {
      return CustomSliverGrid(decorationImage());
    }
}

Upvotes: 1

Wesley Barnes
Wesley Barnes

Reputation: 671

I don't know if you found an answer, but these two options worked for me: cacheExtent, shrinkWrap false. You can make the cacheExtent more or less. I'm sure if it's too much it consumes too much memory as list builder manages the memory for you as it builds and destroys.

CustomScrollView(
    cacheExtent: 3500,
    shrinkWrap: false,
    controller: _scrollController,
    slivers: <Widget>[
      SliverGrid(
        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisCount: 3,
          mainAxisSpacing: 1.5,
          crossAxisSpacing: 1.5,
          childAspectRatio: 0.7,
        ),

Upvotes: 3

Related Questions