Majid Hajian Majid is a Google Developer Expert, an award-winning author, Flutter, PWA, a perf enthusiast, and a passionate software developer with years of developing and architecting complex web and mobile applications.

Implementing SVG in Flutter with flutter_svg

4 min read 1204

implement SVG flutter apps feature image

Scalable Vector Graphics (SVG) is one of the most widely used file image formats in applications. Because it offers several advantages over bitmap files, especially when it comes to retaining image quality while scaling, it’s difficult to start building a Flutter application without first considering using SVG.

In this article, you’ll learn how and when to use SVG files in a Flutter application.

Using SVG in Flutter

Skia, a 2D graphics library and core component of Flutter, can only serialize images into SVG files. Thus, decoding or rendering SVG images with Skia is not possible. Fortunately, the community comes to the rescue with a fantastic Dart-native package called flutter_svg that renders and decodes SVG quickly.

What is flutter_svg?

The flutter_svg package has implemented a picture cache that stores a ui:Picture class. This is the SkPicture wrapper of the Skia graphics engine, which records specific SVG rendering commands in binary mode.

The ui.Picture class does not consume much memory and is cached to avoid repeatedly parsing XML files. Let’s take a look at the SvgPicture.asset constructor:

SvgPicture.asset(
  String assetName, {
  Key? key,
  this.matchTextDirection = false,
  AssetBundle? bundle,
  String? package,
  this.width,
  this.height,
  this.fit = BoxFit.contain,
  this.alignment = Alignment.center,
  this.allowDrawingOutsideViewBox = false,
  this.placeholderBuilder,
  Color? color,
  BlendMode colorBlendMode = BlendMode.srcIn,
  this.semanticsLabel,
  this.excludeFromSemantics = false,
  this.clipBehavior = Clip.hardEdge,
  this.cacheColorFilter = false,
})  : pictureProvider = ExactAssetPicture(
        allowDrawingOutsideViewBox == true
            ? svgStringDecoderOutsideViewBox
            : svgStringDecoder,
        assetName,
        bundle: bundle,
        package: package,
        colorFilter: svg.cacheColorFilterOverride ?? cacheColorFilter
            ? _getColorFilter(color, colorBlendMode)
            : null,
      ),
      colorFilter = _getColorFilter(color, colorBlendMode),
      super(key: key);

By looking at the implementation, you’ll notice that the stream notifications from pictureProvider update the picture of SvgPicture.

 void _resolveImage() {
final PictureStream newStream = widget.pictureProvider
.resolve(createLocalPictureConfiguration(context));
assert(newStream != null); // ignore: unnecessary_null_comparison
_updateSourceStream(newStream);
}

In this code block, the stream from the pictureProvider is populated with ui.Picture by a completer of the picture cache.

PictureStream resolve(PictureConfiguration picture,
    {PictureErrorListener? onError}) {
  // ignore: unnecessary_null_comparison
  assert(picture != null);
  final PictureStream stream = PictureStream();
  T? obtainedKey;
  obtainKey(picture).then<void>(
    (T key) {
      obtainedKey = key;
      stream.setCompleter(
        cache.putIfAbsent(
          key!,
          () => load(key, onError: onError),
        ),
      );
    },
  ).catchError((Object exception, StackTrace stack) async {
    if (onError != null) {
      onError(exception, stack);
      return;
    }
    FlutterError.reportError(FlutterErrorDetails(
        exception: exception,
        stack: stack,
        library: 'SVG',
        context: ErrorDescription('while resolving a picture'),
        silent: true, // could be a network error or whatnot
        informationCollector: () sync* {
          yield DiagnosticsProperty<PictureProvider>(
              'Picture provider', this);
          yield DiagnosticsProperty<T>('Picture key', obtainedKey,
              defaultValue: null);
        }));
  });
  return stream;
}

Adding the flutter_svg plugin

To add this package to your Flutter dependencies, you can run:

flutter pub add flutter_svg

Alternatively, you can add flutter_svg to your pubspec.yaml file:

dependencies:
  flutter_svg: ^0.22.0

Make sure that you run flutter pub get either in your terminal or using your editor. Once installation is complete, import the package in your Dart code where you want to use this package:

We made a custom demo for .
No really. Click here to check it out.

import 'package:flutter_svg/flutter_svg.dart';

Using flutter_svg in your Flutter app

There are several ways to use this package, but we’ll cover the most common use cases.

One option is to load an SVG from an internal SVG file, which is typically stored in the asset folder:

// example
final String assetName = 'assets/image.svg';
final Widget svg = SvgPicture.asset(
assetName,
);

You can also load an SVG file from an URL, like so:

// example
final Widget networkSvg = SvgPicture.network(
  'https://site-that-takes-a-while.com/image.svg',
);

Finally, you can load an SVG from an SVG code:

// example
SvgPicture.string(
  '''<svg viewBox="...">...</svg>'''
);

Extending SVG functionalities in Flutter

Once you have your SVG file loaded, the first step is to change the color or tint of the image:

// example
final String assetName = 'assets/up_arrow.svg';
final Widget svgIcon = SvgPicture.asset(
  assetName,
  color: Colors.red,
);

Using a semantics label helps to describe the purpose of the image and enhances accessibility. To achieve this, you can add the semanticsLabel parameter. The semantic label will not be shown in the UI.

// example
final String assetName = 'assets/up_arrow.svg';
final Widget svgIcon = SvgPicture.asset(
  assetName,
  color: Colors.red,
  semanticsLabel: 'A red up arrow'
);

The flutter_svg package renders an empty box, LimitedBox, as the default placeholder if there are no height or width assignments on the SvgPicture. However, if a height or width is specified on the SvgPicture, a SizedBox will be rendered to ensure a better layout experience.

The placeholder can be replaced, though, which is great for improving the user experience, especially when loading assets via a network request where there may be a delay.

// example
final Widget networkSvg = SvgPicture.network(
  'https://site-that-takes-a-while.com/image.svg',
  semanticsLabel: 'A shark?!',
  placeholderBuilder: (BuildContext context) => Container(
      padding: const EdgeInsets.all(30.0),
      child: const CircularProgressIndicator()),
);

In this example, I’ve chosen CircularProgressIndicator to display a progress indicator while the image is loading. You may add any other widget that you wish. For example, you might use a custom loading widget to replace CircularProgressIndicator.

Checking SVG compatibility with flutter_svg

You should know that the flutter_svg library does not support all SVG features. The package does, however, provide a helper method to ensure that you don’t render a broken image due to a lack of supported features.

// example 
final SvgParser parser = SvgParser();
try {
  parser.parse(svgString, warningsAsErrors: true);
  print('SVG is supported');
} catch (e) {
  print('SVG contains unsupported features');
}

Please note that the library currently only detects unsupported elements like the <style> tag, but does not recognize unsupported attributes.

Recommended Adobe Illustrator SVG configuration

To use make the most use of flutter_svg with Adobe Illustrator, you need to follow specific recommendations:

      • Styling: choose presentation attributes instead of inline CSS because CSS is not fully supported
      • Images: choose to embed, not link, to another file to get a single SVG with no dependency on other files
      • Objects IDs: choose layer names in order to add a name to every layer for SVG tags, or use minimal layer names — the choice is yours!

SVG flutter image options

Rendering SVG files in another canvas

There may be times where you’d like to render your SVG into another canvas. SVGPicture helps you easily achieve this:

// example
final String rawSvg = '''<svg viewBox="...">...</svg>''';
final DrawableRoot svgRoot = await svg.fromSvgString(rawSvg, rawSvg);
final Picture picture = svgRoot.toPicture();
svgRoot.scaleCanvasToViewBox(canvas);
svgRoot.clipCanvasToViewBox(canvas);
svgRoot.draw(canvas, size);

Conclusion

Using SVG files can be a great addition to your Flutter app, but SVG isn’t always the right answer to all of your image problems. It’s crucial to observe your use cases and measure your app and SVG performance continuously, as you might need to replace SVG with another standard image format, such as PNG or JPEG.

Although Flutter doesn’t support SVG natively, the Dart-native flutter_svg package has excellent performant and fast support for SVG files. The package is relatively simple to use, too.

Keep in mind that the package version is still below 1.0.0, which can break changes in API. However, the author has done a great job of keeping the API as stable as possible. When using flutter_svg, make sure you always check the last version of the package on pub.dev to stay up to date. Thanks for reading!

Majid Hajian Majid is a Google Developer Expert, an award-winning author, Flutter, PWA, a perf enthusiast, and a passionate software developer with years of developing and architecting complex web and mobile applications.

Testing accessibility with Storybook

One big challenge when building a component library is prioritizing accessibility. Accessibility is usually seen as one of those “nice-to-have” features, and unfortunately, we’re...
Laura Carballo
4 min read

Leave a Reply