.NET MAUI has the ability to use SVG images which is really nice, but I haven't been able to set the color of the SVG image. The official docs state I could use the TintColor in the project file but that's not a good solution as I want to be able to use different colors depending on certain conditions. So can we somehow specify the color of a SVG image?
I just figured out that the Maui Community toolkit has a IconTintColorBehavior that does just want I want.
Usage:
<Image Source="shield.png">
<Image.Behaviors>
<toolkit:IconTintColorBehavior TintColor="Red" />
</Image.Behaviors>
</Image>
namespace
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
In my answer, I describe two techniques that allow you to use SVG vector graphics in a way that the color can change, and, that you can render at different scales:
MAUI has a Path class which can be used to draw curves and complex shapes. Scaling and setting colors can be done by setting Path. When used with Aspect, Fill, Stroke, Width and Height the shapes can change size and colors.
To use Path we need to adjust your SVG. To take you thru it, I present a sample SVG and apply such conversions to it.
Consider a 32x32 SVG that has 3 solid shapes:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<!-- square -->
<path fill="red" d="M 4 4 h 8 v 8 h -8 v -8" />
<!-- triangle -->
<path fill="red" d="M 24 4 l 4 8 h -8 l 4 -8" />
<!-- circle -->
<path fill="red" d="M 16 20 a 4 4 0 0 1 0 8 a 4 4 0 0 1 0 -8" />
</svg>

To prepare it for Path Data we need to make the following changes:
Apply these conversions will result into a new SVG with a single path in it:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<path fill="red" d="
M 0 0 L 32 32 L 0 0
L 4 4 h 8 v 8 h -8 v -8
L 0 0
L 24 4 l 4 8 h -8 l 4 -8
L 0 0
L 16 20
a 4 4 0 0 1 0 8
a 4 4 0 0 1 0 -8
L 0 0" />
</svg>
Note that the things that I did were:
Now that I've made these changes, I can copy the path from the SVG straight into the Path/Data and use it in .NET MAUI XAML like this:
<Border Padding="1" HorizontalOptions="Center">
<Path
Aspect="Uniform"
Data="M 0 0 L 32 32 L 0 0 L 4 4 h 8 v 8 h -8 v -8 L 0 0 L 24 4 l 4 8 h -8 l 4 -8 L 0 0 L 16 20 a 4 4 0 0 1 0 8 a 4 4 0 0 1 0 -8 L 0 0"
Fill="Red"
HeightRequest="100"
WidthRequest="100" />
</Border>
Note that the answer avoided stroke outlines. To do outlines using this approach, one has to define holes in the shapes by drawing the inner polygon hole anticlockwise. Also, we must connect the outer polygon to the inner polygon with a forward and reversing connecting line. After the connecting line, we must connect all polygon parts back to the starting point (e.g. L 0 0).
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<path fill="red" d="
M 0 0 L 32 32 L 0 0
L 4 4 h 8 v 8 h -8 v -8
l 1 1
v 6 h 6 v -6 h -6
l -1 -1
L 0 0
L 24 4 l 4 8 h -8 l 4 -8
v 2
l -2.5 5 h 5 l -2.5 -5
v -2
L 0 0
L 16 20
a 4 4 0 0 1 0 8
a 4 4 0 0 1 0 -8
v 1
a 3 3 0 0 0 0 6
a 3 3 0 0 0 0 -6
v -1
L 0 0" />
</svg>

Convert the above to .NET MAUI Path:
<Border Padding="1" HorizontalOptions="Center">
<Path
Aspect="Uniform"
Data="M 0 0 L 32 32 L 0 0 L 4 4 h 8 v 8 h -8 v -8 l 1 1 v 6 h 6 v -6 h -6 l -1 -1 L 0 0 L 24 4 l 4 8 h -8 l 4 -8 v 2 l -2.5 5 h 5 l -2.5 -5 v -2 L 0 0 L 16 20 a 4 4 0 0 1 0 8 a 4 4 0 0 1 0 -8 v 1 a 3 3 0 0 0 0 6 a 3 3 0 0 0 0 -6 v -1 L 0 0"
Fill="Red"
HeightRequest="100"
WidthRequest="100" />
</Border>
[Original answer involving true type fonts]
If you are looking for a cross-platform vector file format that .NET MAUI natively supports and you are willing to pre-convert, then, consider converting your SVG icons assets to a TTF (true-type font). TTF will keep your icons in vector format and they can be resized and recolored at runtime.
Here are detailed steps on how to do the above.
Install Node.JS / NPM package https://www.npmjs.com/package/fantasticon :
sudo apt update
sudo apt install npm
sudo npm install -g fantasticon
Prepare a conversion workspace:
maui-svg-ttf/scripts/svg/compass.svg
maui-svg-ttf/scripts/svg/globe.svg
maui-svg-ttf/scripts/svg/locator.svg
maui-svg-ttf/scripts/svg/shield.svg
maui-svg-ttf/scripts/makefonts.sh
maui-svg-ttf/scripts/my-icons.js
Here's makefonts.sh:
mkdir -p /tmp/maui-svg-ttf
fantasticon --config my-icons.js
cp /tmp/maui-svg-ttf/my-icons.ttf ../Resources/fonts/my-icons.ttf
Here's my-icons.js:
module.exports = {
name: 'my-icons',
fontHeight: 500,
normalize: true,
inputDir: 'svg',
outputDir: '/tmp/maui-svg-ttf',
fontTypes: ['ttf'],
assetTypes: ['css', 'json', 'html'],
formatOptions: {
json: {
indent: 2
}
},
codepoints: {
'globe' : 0xe000, // globe.svg at 0xe000 codepoint
'compass' : 0x0001, // compass.svg at 0x0001 codepoint
'locator' : 0x0002, // locator.svg at 0x0002 codepoint
'shield' : 0xe003, // shield.svg at 0xe003 codepoint
},
getIconId: ({
basename, // `string` - Example: 'foo';
relativeDirPath, // `string` - Example: 'sub/dir/foo.svg'
absoluteFilePath, // `string` - Example: '/var/icons/sub/dir/foo.svg'
relativeFilePath, // `string` - Example: 'foo.svg'
index // `number` - Example: `0`
}) => {
return basename;
}
};
Make sure your new font my-icons.ttf gets copied to your Resources/fonts/ folder.
// MauiProgram.cs ...
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
fonts.AddFont("my-icons.ttf", "my-icons");
});
builder.Services.AddTransient<MainViewModel>();
builder.Services.AddTransient<MainPage>();
<VerticalStackLayout>
<Label Text="" FontFamily="my-icons" FontSize="{Binding IconSize}" TextColor="{Binding Color}" Rotation="{Binding Angle}" HorizontalOptions="Center"/>
<HorizontalStackLayout HorizontalOptions="Center">
<Image HeightRequest="{Binding IconSize}" WidthRequest="{Binding IconSize}" Rotation="{Binding Angle}">
<Image.Source>
<FontImageSource Glyph="" FontFamily="my-icons" Color="{Binding Color}" Size="{Binding IconSize}" />
</Image.Source>
</Image>
<Image HeightRequest="{Binding IconSize}" WidthRequest="{Binding IconSize}" Rotation="{Binding Angle}">
<Image.Source>
<FontImageSource Glyph="" FontFamily="my-icons" Color="{Binding Color}" Size="{Binding IconSize}" />
</Image.Source>
</Image>
<Image HeightRequest="{Binding IconSize}" WidthRequest="{Binding IconSize}" Rotation="{Binding Angle}">
<Image.Source>
<FontImageSource Glyph="" FontFamily="my-icons" Color="{Binding Color}" Size="{Binding IconSize}" />
</Image.Source>
</Image>
</HorizontalStackLayout>
<Slider Minimum="0" Maximum="255" Value="{Binding RedValue, Mode=TwoWay}"/>
<Slider Minimum="0" Maximum="255" Value="{Binding GreenValue, Mode=TwoWay}"/>
<Slider Minimum="0" Maximum="255" Value="{Binding BlueValue, Mode=TwoWay}"/>
<Slider Minimum="32" Maximum="80" Value="{Binding IconSize, Mode=TwoWay}"/>
<Slider Minimum="0" Maximum="360" Value="{Binding Angle, Mode=TwoWay}"/>
</VerticalStackLayout>
// MainPage.xaml.cs ...
public partial class MainPage : ContentPage
{
public MainPage(MainViewModel VM)
{
InitializeComponent();
BindingContext = VM;
}
}
// MainViewModel.cs ...
public partial class MainViewModel : ObservableObject
{
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(Color))]
int _redValue = 128;
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(Color))]
int _greenValue = 0;
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(Color))]
int _blueValue = 0;
[ObservableProperty]
int _iconSize = 32;
[ObservableProperty]
int _angle = 0;
public Color Color => Color.FromRgb(RedValue, GreenValue, BlueValue);
}

Full source code for the above: https://github.com/stephenquan/maui-svg-ttf
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With