24

I'm using flutter_svg package to render SVG images in my app, as flutter does not officially supports SVG yet.I'm having a delay of probably few seconds while trying to load SVG images in my app and while looking for the solution I found out that I can preload the SVG image using preCachePicture(). The problem is that the official flutter_svg documentation does not clearly states nor there are other web material to show how to use this function to preload SVG images.

I'm calling loadPictures() function in initState() to preload the SVG picture.

String onboardImage = 'assets/images/onboard.svg';

@override
  void initState() {
    loadPictures();
    super.initState();
  }

  Future<void> loadPictures() async {
    await precachePicture(ExactAssetPicture((SvgPicture.svgStringDecoder),onboardImage), null);    
  } 

After calling preCachePicture(), How to load the precached image when I wanted to use it ?

Shubhamhackz
  • 7,333
  • 7
  • 50
  • 71
  • 1
    the docs say: *"If the image is later used by an SvgPicture, it will probably be loaded faster. The consumer of the image does not need to use the same PictureProvider instance. The PictureCache will find the picture as long as both pictures share the same key."* – pskink Jun 08 '20 at 07:38
  • 1
    @pskink I see but can you explain the docs? – Shubhamhackz Jun 08 '20 at 07:41
  • @pskink Can you answer where to put the keys? As SvgPicture takes a key as an argument but preCachePicture doesn't seems to take key in constructer. – Shubhamhackz Jun 15 '20 at 09:15
  • you need to use the same `PictureProvider` - both in `preCachePicture` and `SvgPicture` – pskink Jun 15 '20 at 09:24

4 Answers4

29

To cache multiple SVGs, do this:

Future.wait([
  precachePicture(
    ExactAssetPicture(
      SvgPicture.svgStringDecoder, // See UPDATE below!
      'assets/my_icon.svg',
    ),
    null,
  ),
  precachePicture(
    ExactAssetPicture(
      SvgPicture.svgStringDecoder, // See UPDATE below!
      'assets/my_asset.svg',
    ),
    null,
  ),
  // other SVGs or images here
]);

Note: do this in main.dart, or in a widget which is displayed before the widget which uses the SVG. For example, you can do it on splash screen if you need an svg for login or signup.


UPDATE: as per riccardogabellone's comment, since late 2021, instead of SvgPicture.svgStringDecoder we should use SvgPicture.svgStringDecoderOutsideViewBoxBuilder or SvgPicture.svgStringDecoderBuilder.

Aleksandar
  • 3,558
  • 1
  • 39
  • 42
9

2023 UPDATE: flutter_svg 2.0.0+1

You could have noticed that precachePicture has been deprecated. hygehyge has come up with a new working solution:

const loader = SvgAssetLoader('res/large_icon.svg');
svg.cache.putIfAbsent(loader.cacheKey(null), () => loader.loadBytes(null));
faccio
  • 652
  • 3
  • 16
8

Calling precache in your widget's initState is too late. You should instead call this method in the main() function like this:

Future<void> main() async {
    await precachePicture(ExactAssetPicture(SvgPicture.svgStringDecoder, 'assets/images/onboard.svg'), null);
    runApp(YourApp());
}
0

adding to the answer @faccio has already provided, we can also create a precache function.. the Future.wait ensures you can cache multiple items

main.dart

void main() async {
  await precacheInitialAssets();
  runApp(const MyApp());
}

precacheInitialAssets() async {
  await Future.wait([
  precacheSvgPicture('assets/svg/logo.svg'),
]);
}

helpers.dart

Future precacheSvgPicture(String svgPath) async {
  final logo = SvgAssetLoader(svgPath);
  await svg.cache.putIfAbsent(logo.cacheKey(null), () => logo.loadBytes(null));
}

but i would not advice precaching all your assets on the main.dart, just the initial once, then some others in the initstate of your splash screen

Belema
  • 699
  • 6
  • 6