.NET Maui中如何显示下载后的SVG图片?
.NET MAUI 本地/URL加载SVG显示解决方案
问题背景
我们的应用中SVG图片分两类:
- 嵌入资源的SVG:通过转换器修改扩展名为
.png即可正常显示 - RestService加载的SVG(用户可自行添加命名):从URL、
Microsoft.Maui.Storage.FileSystem.AppDataDirectory或Environment.SpecialFolder.LocalApplicationData路径加载时,无论是直接用.svg扩展名还是转.png都无法显示。之前Xamarin.Forms用FFImageLoading实现,迁移到.NET MAUI后找不到合适方案。
现有代码
下载SVG文件代码
private async Task DownloadIcons(List<DownloadIcon> downloadIcons) { var lightIconsFolderPath = Path.Combine(iconFolderPath, lightIconFolderName); var darkIconsFolderPath = Path.Combine(iconFolderPath, darkIconFolderName); DirectoryManager(lightIconsFolderPath); DirectoryManager(darkIconsFolderPath); CurrentIcons = new List<Icon>(); foreach (var downloadIcon in downloadIcons) { Icon icon = new Icon(); icon.IconId = downloadIcon.IconId; var ligthIconBytes = await DownloadIconFromURL(downloadIcon.LightThemeIconLink); icon.LightThemeIconPath = await WriteIconToDisk(lightIconsFolderPath, ligthIconBytes, downloadIcon.IconTranslations[0].Name); var darkIconBytes = await DownloadIconFromURL(downloadIcon.DarkThemeIconLink); icon.DarkThemeIconPath = await WriteIconToDisk(darkIconsFolderPath, darkIconBytes, downloadIcon.IconTranslations[0].Name); CurrentIcons.Add(icon); } } private async Task<byte[]> DownloadIconFromURL(string downloadedIconUrl) { try { byte[] bytes; using (HttpClient httpClient = new HttpClient()) { bytes = await httpClient.GetByteArrayAsync(downloadedIconUrl); } return bytes; } catch (System.Exception e) { log.Error("Exception while trying to download icon from url", e); return null; } }
写入磁盘代码
private async Task<string> WriteIconToDisk(string pathToIconsFolder, byte[] iconBytes, string iconName) { try { string fileName = ""; string namingConventionName = ModifyLowerCaseLetterString(iconName); fileName = Path.Combine(pathToIconsFolder, $"{namingConventionName}.svg"); File.WriteAllBytes(fileName, iconBytes); return fileName; } catch (System.Exception e) { log.Error("Exception while trying to write icon on device", e); return null; } }
XAML图片控件
<Image HeightRequest="24" Source="{Binding Icon.ActiveIconPath, Converter={StaticResource SvgImageSourceConverter}}" WidthRequest="24" />
转换器处理后路径示例:/storage/emulated/0/Android/data/[company]/files/icons/light/light.png,尝试.svg扩展名也无法显示。
解决方案
方案1:使用FFImageLoading.Maui(原库迁移版)
- 安装NuGet包:
FFImageLoading.Maui及FFImageLoading.Svg.Maui - 初始化配置:在MauiProgram.cs中添加:
builder.UseFFImageLoading(); builder.ConfigureFFImageLoading(options => { options.SkipMemoryCache = false; options.DiskCacheDuration = TimeSpan.FromDays(30); });
- 替换XAML控件:用
CachedImage替代原生Image,并指定SVG解码:
<ffimageloading:CachedImage HeightRequest="24" WidthRequest="24" Source="{Binding Icon.ActiveIconPath}" DownsampleToViewSize="True"> <ffimageloading:CachedImage.Transformations> <fftransformations:SvgTransformation /> </ffimageloading:CachedImage.Transformations> </ffimageloading:CachedImage>
无需再修改扩展名,直接传入.svg路径即可,支持本地文件、URL、嵌入资源。
方案2:使用SkiaSharp.Svg手动渲染
- 安装NuGet包:
SkiaSharp.Views.Maui和SkiaSharp.Svg - 自定义转换器:创建
SvgToImageSourceConverter,将SVG文件转为ImageSource:
public class SvgToImageSourceConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value is string path && File.Exists(path)) { using var svg = new SKSvg(); svg.Load(path); var bitmap = new SKBitmap((int)svg.CanvasSize.Width, (int)svg.CanvasSize.Height); using var canvas = new SKCanvas(bitmap); canvas.Clear(SKColors.Transparent); canvas.DrawPicture(svg.Picture); return ImageSource.FromStream(() => { var stream = new MemoryStream(); bitmap.Encode(stream, SKEncodedImageFormat.Png, 100); stream.Position = 0; return stream; }); } return null; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } }
- XAML中使用:保持原有
Image控件,替换转换器为自定义的SvgToImageSourceConverter,传入.svg路径即可。
注意事项
- 若使用FFImageLoading,需确保权限配置正确(如Android的网络权限、文件读取权限)
- SkiaSharp方案可根据View尺寸调整SVG渲染大小,适配不同显示需求
内容的提问来源于stack exchange,提问作者KarsaOrlong1981
相关产品推荐
相关产品推荐

