It's a free, MIT-licenced icon from IconFinder; you can download it from there.
In practice, you probably wouldn't render an icon in this way; that's what icon fonts are designed for. It's just a small SVG that serves as an example of this approach.
The SVG version looks like this:
<svg height="48" viewBox="0 0 48 48" width="48" xmlns="http://www.w3.org/2000/svg">
<path d="M20 40V28h8v12h10V24h6L24 6 4 24h6v16z"/>
<path d="M0 0h48v48H0z" fill="none"/>
</svg>
The Jovial SVG package allows you to use SVG images in your Flutter app, typically from SVG files in your assets folders, or a more efficient binary format.
It also allows you to render an SVG from its underlying string representation; that's what we're going to do here.
flutter pub add jovial_svg
You'll need to import it:
import 'package:jovial_svg/jovial_svg.dart';
In order to display an SVG, you need to create a ScalableImageWidget
. This takes an instance of the ScalableImage
class. That class has a number of named constructors; among them, fromSvgString()
.
Let's look at how to do that.
class HomeIcon extends StatelessWidget {
const HomeIcon({super.key});
static const svgStr = '''<svg height="48" viewBox="0 0 48 48" width="48" xmlns="http://www.w3.org/2000/svg">
<path d="M20 40V28h8v12h10V24h6L24 6 4 24h6v16z"/>
<path d="M0 0h48v48H0z" fill="none"/>
</svg>''';
@override
Widget build(BuildContext context) {
return ScalableImageWidget(
si: ScalableImage.fromSvgString(svgStr),
);
}
}
Here we're creating a constant variable to hold the SVG code, creating an instance of ScalableImage
using its fromSvgString()
named constructor, and creating a ScalableImageWidget
for it.
Let's improve this. For starters, the whole point of a scalable image is, well, that it can scale; being a vector, it can scale up without any degradation in quality.
ScalableImageWidget
takes a scale
property, which is a double
; a value of 3
means it should be doubled in size, 0.5
means it should be halved.
That's only one way we can modify the image's size; the other is to place it in a SizedBox
and instruct it to fill the space:
SizedBox(
width: size,
child: ScalableImageWidget(
si: ScalableImage.fromSvgString(svgStr),
fit: BoxFit.cover,
)
)
Before we use that in the code, let's add another enhancement. One of the benefits of embedding an SVG image using a string, is that we can modify it; for example, dynamically changing the color or showing/hiding parts of an image. It also supports inline stylesheets to do similar.
Let's add a color
property, then use that to dynamically set the color of the image.
We'll use an instance of Color
, but we'll need a hexadecimal representation. Here's an easy way to do that:
color.value.toRadixString(16)
Let's put all of that together to create a new icon widget:
class HomeIconCustom extends StatelessWidget {
const HomeIconCustom({
super.key,
Color? color,
double? size,
}): color = color ?? Colors.black, size = size ?? 48;
final Color color;
final double size;
@override
Widget build(BuildContext context) {
String svgStr = """<svg height="48" viewBox="0 0 48 48" width="48" xmlns="http://www.w3.org/2000/svg">
<path d="M20 40V28h8v12h10V24h6L24 6 4 24h6v16z" fill="#${color.value.toRadixString(16)}" />
<path d="M0 0h48v48H0z" fill="none"/>
</svg>""";
return SizedBox(
width: size,
child: ScalableImageWidget(
si: ScalableImage.fromSvgString(svgStr),
fit: BoxFit.cover,
)
);
}
}
Here's all of the code above as a fully-fledged Flutter app:
import 'package:flutter/material.dart';
import 'package:jovial_svg/jovial_svg.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
HomeIcon(),
HomeIconCustom(),
HomeIconCustom(color: Colors.red,),
],
)
),
),
);
}
}
class HomeIcon extends StatelessWidget {
const HomeIcon({super.key});
static const svgStr = '''<svg height="48" viewBox="0 0 48 48" width="48" xmlns="http://www.w3.org/2000/svg">
<path d="M20 40V28h8v12h10V24h6L24 6 4 24h6v16z"/>
<path d="M0 0h48v48H0z" fill="none"/>
</svg>''';
@override
Widget build(BuildContext context) {
return ScalableImageWidget(
si: ScalableImage.fromSvgString(svgStr),
);
}
}
class HomeIconCustom extends StatelessWidget {
const HomeIconCustom({
super.key,
Color? color,
double? size,
}): color = color ?? Colors.black, size = size ?? 48;
final Color color;
final double size;
@override
Widget build(BuildContext context) {
String svgStr = """<svg height="48" viewBox="0 0 48 48" width="48" xmlns="http://www.w3.org/2000/svg">
<path d="M20 40V28h8v12h10V24h6L24 6 4 24h6v16z" fill="#${color.value.toRadixString(16)}" />
<path d="M0 0h48v48H0z" fill="none"/>
</svg>""";
return SizedBox(
width: size,
child: ScalableImageWidget(
si: ScalableImage.fromSvgString(svgStr),
fit: BoxFit.cover,
)
);
}
}