Draw SVG and Android VectorDrawable (XML) files on a Flutter Widget.
This is a Dart-native rendering library. Issues/PRs will be raised in Flutter and flutter/engine as necessary for features that are not good candidates for Dart implementations (especially if they're impossible to implement without engine support). However, not everything that Skia can easily do needs to be done by Skia; for example, the Path parsing logic here isn't much slower than doing it in native, and Skia isn't always doing low level GPU accelerated work where you might think it is (e.g. Dash Paths).
All of the SVGs in the assets/
folder (except the text related one(s)) now
have corresponding PNGs in the golden/
folder that were rendered using
flutter test tool/gen_golden.dart
and compared against their rendering output
in Chrome. Automated tests will continue to compare these to ensure code
changes do not break known-good renderings.
Basic usage (to create an SVG rendering widget from an asset):
final String assetName = 'assets/image.svg';
final Widget svg = new SvgPicture.asset(
assetName,
);
You can color/tint the image like so:
final String assetName = 'assets/icon.svg';
final Widget svgIcon = new SvgPicture.asset(
assetName,
color: Colors.red,
);
The default placeholder is an empty box (LimitedBox
) - although if a height
or
width
is specified on the SvgPicture
, a SizedBox
will be used instead (which
ensures better layout experience). There is currently no way to show an
Error visually, however errors will get properly logged to the console in debug
mode.
You can also specify a placeholder widget. The placeholder will display during parsing/loading (normally only relevant for network access).
// Will print error messages to the console.
final String assetName = 'assets/image_that_does_not_exist.svg';
final Widget svg = new SvgPicture.asset(
assetName,
);
final Widget networkSvg = new SvgImage.network(
'https://site-that-takes-a-while.com/image.svg',
loadingPlaceholderBuilder: (BuildContext context) => new Container(
padding: const EdgeInsets.all(30.0),
child: const CircularProgressIndicator()),
);
If you'd like to render the SVG to some other canvas, you can do something like:
import 'package:flutter_svg/flutter_svg.dart';
final DrawableRoot svgRoot = await svg.loadAsset('assets/image.svg');
// If you only want the final Picture output, just use
final Picture picture = svgRoot.toPicture();
// Otherwise, if you want to draw it to a canvas:
// Optional, but probably normally desirable: scale the canvas dimensions to
// the SVG's viewbox
svgRoot.scaleCanvasToViewBox(canvas);
// Optional, but probably normally desireable: ensure the SVG isn't rendered
// outside of the viewbox bounds
svgRoot.clipCanvasToViewBox(canvas);
svgRoot.draw(canvas, size);
The SvgPicture
helps to automate this logic, and it provides some convenience
wrappers for getting assets from multiple sources and caching the resultant
Picture
. It does not render the data to an Image
at any point; you certainly
can do that in Flutter, but you then lose some of the benefit of having a vector
format to begin with.
While I'm making every effort to avoid needlessly changing the API, it's not
guarnateed to be stable yet (hence the pre-1.0.0 version). To date, the biggest change
is deprecating the SvgImage
widgets in favor of SvgPicture
- it became very confusing
to maintain that name, as Picture
s are the underlying mechanism for rendering
rather than Image
s.
See main.dart for a complete sample.
This list is not very well ordered. I'm mainly picking up things that seem interesting or useful, or where I've gotten a request to fix something/example of something that's broken.
SVGs in /assets/w3samples
pulled from W3 sample files
SVGs in /assets/deborah_ufw
provided by @deborah-ufw
SVGs in /assets/simple
are pulled from trivial examples or generated to test
basic functionality - some of them come directly from the SVG 1.1 spec.
SVGs in /assets/wikimedia
are pulled from Wikimedia Commons
Android Drawables in assets/android_vd
are pulled from Android Documentation and examples.
The Flutter Logo created based on the Flutter Logo Widget © Google.
The Dart logo is from dartlang.org © Google
Please submit SVGs this can't render properly (e.g. that don't render here the way they do in chrome), as long as they're not using anything "probably out of scope" (above).
HttpStatus.OK
change - not ready yet for Flutter beta channel<tspan>
stylestext-anchor
attribute<ellipse>
parsing bug (ellipses were drawn at half the expected size)<polyline>
parsing bug (polylines were incorrectly forced to be closed)FittedBox
width
and height
properties to SvgPicture
SvgImage
matchesTextDirection
text-anchor
SvgImage
, AvdImage
, and VectorDrawableImage
have been
deprecated. They relied on methods that are less efficient than those
now surfaced in SvgPicture
.SvgPicture
- its size is
determined by parent size.clipToViewBox
is now called allowDrawingOutsideViewBox
.
It defaults to false. It should not ordinarily be set to true, as it can allow
unexpected memory usage if your vector graphic tries to draw far outside of
the viewBox bounds.SvgPicture
does not support custom ErrorWidgetBuilder
s at
this point in time. However, errors will be properly logged to the console.
This is a result of improvements in the loading/caching of drawings.<clipPath>
s<radialGradient>
percentage handling.Bumping minor version due to internal breaking changes and new support. Works on dev channel as of release (Flutter >= 0.3.6).
DrawableRoot
to support top level style definition.@style
attributes.rgb()
color attribute/styles.assets/simple/style_attr.svg
).Initial text support. Relies on flutter 0.3.6.
Initial release. Relies on pre-released master.
example/main.dart
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_svg/avd.dart';
import 'package:flutter_svg/flutter_svg.dart';
const List<String> assetNames = const <String>[
// 'assets/notfound.svg',
'assets/flutter_logo.svg',
'assets/dart.svg',
'assets/simple/clip_path_3.svg',
'assets/simple/clip_path_2.svg',
'assets/simple/clip_path.svg',
'assets/simple/group_fill_opacity.svg',
'assets/simple/group_opacity.svg',
'assets/simple/text.svg',
'assets/simple/linear_gradient.svg',
'assets/simple/linear_gradient_2.svg',
'assets/simple/radial_gradient.svg',
'assets/simple/rect_rrect.svg',
'assets/simple/style_attr.svg',
'assets/w3samples/aa.svg',
'assets/w3samples/alphachannel.svg',
'assets/simple/ellipse.svg',
'assets/simple/dash_path.svg',
'assets/simple/nested_group.svg',
'assets/wikimedia/chess_knight.svg',
'assets/wikimedia/Ghostscript_Tiger.svg',
];
const List<String> iconNames = const <String>[
'assets/deborah_ufw/new-action-expander.svg',
'assets/deborah_ufw/new-camera.svg',
'assets/deborah_ufw/new-gif-button.svg',
'assets/deborah_ufw/new-gif.svg',
'assets/deborah_ufw/new-image.svg',
'assets/deborah_ufw/new-mention.svg',
'assets/deborah_ufw/new-pause-button.svg',
'assets/deborah_ufw/new-play-button.svg',
'assets/deborah_ufw/new-send-circle.svg',
'assets/deborah_ufw/numeric_25.svg',
];
const List<String> uriNames = const <String>[
'http://upload.wikimedia.org/wikipedia/commons/0/02/SVG_logo.svg',
'https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/410.svg',
'https://upload.wikimedia.org/wikipedia/commons/b/b4/Chess_ndd45.svg',
];
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter SVG Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final List<Widget> _painters = <Widget>[];
double _dimension;
@override
void initState() {
super.initState();
_dimension = 250.0;
_painters.add(new SvgPicture.string('<svg viewBox="0 0 120 120"><path d="M20,30 Q40,5 60,30 T100,30" stroke="red" fill="none"/></svg>'));
for (String assetName in assetNames) {
_painters.add(
new SvgPicture.asset(assetName),
);
}
for (int i = 0; i < iconNames.length; i++) {
_painters.add(
new Directionality(
textDirection: TextDirection.ltr,
child: new SvgPicture.asset(
iconNames[i],
color: Colors.blueGrey[(i + 1) * 100],
matchTextDirection: true,
),
),
);
}
// _painters.add(new SvgPicture.asset(iconNames[0], color: Colors.red));
for (String uriName in uriNames) {
_painters.add(
new SvgPicture.network(
uriName,
placeholderBuilder: (BuildContext context) => new Container(
padding: const EdgeInsets.all(30.0),
child: const CircularProgressIndicator()),
),
);
}
_painters
.add(new AvdPicture.asset('assets/android_vd/battery_charging.xml'));
}
@override
Widget build(BuildContext context) {
if (_dimension > MediaQuery.of(context).size.width - 10.0) {
_dimension = MediaQuery.of(context).size.width - 10.0;
}
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new Column(children: <Widget>[
new Slider(
min: 5.0,
max: MediaQuery.of(context).size.width - 10.0,
value: _dimension,
onChanged: (double val) {
setState(() => _dimension = val);
}),
// new FlutterLogo(size: _dimension),
// new Container(
// padding: const EdgeInsets.all(12.0),
// child:
// )
new Expanded(
child: new GridView.extent(
shrinkWrap: true,
maxCrossAxisExtent: _dimension,
padding: const EdgeInsets.all(4.0),
mainAxisSpacing: 4.0,
crossAxisSpacing: 4.0,
children: _painters.toList(),
),
),
]),
);
}
}
Add this to your package's pubspec.yaml file:
dependencies:
flutter_svg: ^0.5.4
You can install packages from the command line:
with Flutter:
$ flutter packages get
Alternatively, your editor might support flutter packages get
.
Check the docs for your editor to learn more.
Now in your Dart code, you can use:
import 'package:flutter_svg/flutter_svg.dart';
Version | Uploaded | Documentation | Archive |
---|---|---|---|
0.10.3 | Jan 25, 2019 |
|
|
0.10.2 | Jan 17, 2019 |
|
|
0.10.1 | Jan 14, 2019 |
|
|
0.10.0+2 | Jan 14, 2019 |
|
|
0.10.0+1 | Jan 13, 2019 |
|
|
0.10.0 | Jan 12, 2019 |
|
|
0.9.0+1 | Dec 31, 2018 |
|
|
0.9.0 | Dec 31, 2018 |
|
|
0.8.3 | Dec 29, 2018 |
|
|
0.8.2 | Dec 18, 2018 |
|
|
Popularity:
Describes how popular the package is relative to other packages.
[more]
|
99
|
Health:
Code health derived from static analysis.
[more]
|
100
|
Maintenance:
Reflects how tidy and up-to-date the package is.
[more]
|
88
|
Overall:
Weighted score of the above.
[more]
|
97
|
We analyzed this package on Feb 4, 2019, and provided a score, details, and suggestions below. Analysis was completed with status completed using:
Detected platforms: Flutter
References Flutter, and has no conflicting libraries.
Fix lib/src/picture_provider.dart
. (-0.50 points)
Analysis of lib/src/picture_provider.dart
reported 1 hint:
line 484 col 43: 'OK' is deprecated and shouldn't be used.
The package description is too short. (-12 points)
Add more detail to the description
field of pubspec.yaml
. Use 60 to 180 characters to describe the package, what it does, and its target use case.
Package | Constraint | Resolved | Available |
---|---|---|---|
Direct dependencies | |||
Dart SDK | >=1.19.0 <3.0.0 | ||
flutter | 0.0.0 | ||
meta | ^1.1.2 | 1.1.6 | 1.1.7 |
path_drawing | ^0.3.0 | 0.3.1 | 0.4.0 |
vector_math | ^2.0.4 | 2.0.8 | |
xml | ^3.0.0 | 3.3.1 | |
Transitive dependencies | |||
charcode | 1.1.2 | ||
collection | 1.14.11 | ||
convert | 2.1.1 | ||
path_parsing | 0.1.3 | ||
petitparser | 2.1.1 | ||
sky_engine | 0.0.99 | ||
typed_data | 1.1.6 | ||
Dev dependencies | |||
flutter_test | |||
mockito | ^2.2.3 | ||
path | ^1.5.1 | ||
test | ^0.12.34 |