Xamarin.Forms如何将Button的ImageSource设置为ffimageloading中嵌入资源的Svg?

4

我想将一个嵌入式的 svg 图像作为 Xamarin.Forms 中的 ButtonImageSource,类似于以下示例

<Button Text="Button" ImageSource="resource://fullname.svg">
</Button>

可能会对svg应用变换(来自FFImageLoading.Transformations),但这只是额外的。

我已经尝试了这个语法

<Button Text="Button"
  ImageSource="{ext:ImageResourceExtension fullname.svg}" />

c#

    public class ImageResourceExtension : IMarkupExtension
    {
        private static Assembly Assembly = typeof(ImageResourceExtension).GetTypeInfo().Assembly;

        public string Source { get; set; }

        public object ProvideValue(IServiceProvider serviceProvider)
        {
            if (Source == null) return null;
            return SvgImageSource.FromResource(Source, Assembly, 32, 32);

        }
   }

但是它没有起作用。

此外,我无法使这个语法起作用。

Source="{resource://fullname.svg, Converter={StaticResource SvgImageSourceConverter}}"

需要帮忙吗? 谢谢


https://github.com/luberda-molinet/FFImageLoading/wiki/SVG-support - Jason
@Jason,谢谢,我已经尝试过了,但是我无法让它工作。 - ʞᴉɯ
“不能让它工作”不是问题的有用描述。 - Jason
@Jason,你说得对,我已经更新了问题。 - ʞᴉɯ
2个回答

4

正如Jason所说,FFImageLoading支持SVG文件。按照以下步骤操作:

在Xamarin.Forms中创建一个资源文件夹而不是Android部分。然后将SVG文件作为嵌入式资源添加。

enter image description here

用法:使用SvgCachedImage显示嵌入式SVG图像,并使用TapGestureRecognizer模拟按钮单击事件。

<ffimageloadingsvg:SvgCachedImage
            HeightRequest="50"
            Source="resource://XamarinDemo.Resources.brightness2.svg"
            WidthRequest="50">
            <ffimageloadingsvg:SvgCachedImage.GestureRecognizers>
                <TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped"></TapGestureRecognizer>
            </ffimageloadingsvg:SvgCachedImage.GestureRecognizers>
        </ffimageloadingsvg:SvgCachedImage>

不要忘记添加命名空间。

xmlns:ffimageloadingsvg="clr-namespace:FFImageLoading.Svg.Forms;assembly=FFImageLoading.Svg.Forms"

enter image description here

更新:我们可以使用SkiaSharp来绘制一个 SVG 文件的图像。

MyControl.cs

public class MyControl : Frame
{
    private readonly SKCanvasView _canvasView = new SKCanvasView();
    public MyControl()
    {
        Padding = new Thickness(0);
        BackgroundColor = Color.Transparent;
        Content = _canvasView;

        _canvasView.PaintSurface += CanvasViewOnPaintSurface;
    }
    public static readonly BindableProperty ImageProperty = BindableProperty.Create(
       nameof(Image), typeof(string), typeof(MyControl), default(string), propertyChanged: RedrawCanvas);

    public string Image
    {
        get => (string)GetValue(ImageProperty);
        set => SetValue(ImageProperty, value);
    }
    private static void RedrawCanvas(BindableObject bindable, object oldvalue, object newvalue)
    {
        MyControl svgIcon = bindable as MyControl;
        svgIcon?._canvasView.InvalidateSurface();
    }
    private void CanvasViewOnPaintSurface(object sender, SKPaintSurfaceEventArgs e)
    {
        SKCanvas canvas = e.Surface.Canvas;
        canvas.Clear();


        using (Stream stream = GetType().Assembly.GetManifestResourceStream(Image))
        {
            SkiaSharp.Extended.Svg.SKSvg svg = new SkiaSharp.Extended.Svg.SKSvg();
            svg.Load(stream);

            SKImageInfo info = e.Info;
            canvas.Translate(info.Width / 2f, info.Height / 2f);

            SKRect bounds = svg.ViewBox;
            float xRatio = info.Width / bounds.Width;
            float yRatio = info.Height / bounds.Height;

            float ratio = Math.Min(xRatio, yRatio);

            canvas.Scale(ratio);
            canvas.Translate(-bounds.MidX, -bounds.MidY);

            canvas.DrawPicture(svg.Picture);

        }
    }
}

使用方法:

<local:MyControl
            HeightRequest="50"
            Image="XamarinDemo.Resources.brightness2.svg"
            WidthRequest="50" />

您可以使用 TapGestureRecognizer 来模拟按钮点击事件。


谢谢您的回答,我已经以那种方式使用ffimageloading了,问题在于将其用作ImageSource。 - ʞᴉɯ
我找不到以图像源的方式加载,但我们可以制作自定义控件来加载。我已经更新了我的回复。 - Wendy Zang - MSFT

2
更新了适用于Xamarin的原始图像资源扩展类。OP的类存在两个问题:
  1. 缺少ContentProperty属性,该属性允许跳过“源”属性名称。
  2. 将部分资源名称转换为完整资源名称的部分。
添加了可选的“Assembly”属性,该属性允许指定不同的程序集。在代码中,您还可以使用可选的“替换字符串映射”获取完整名称、资源路径和ImageSource对象,从而允许动态修改原始SVG内容,例如颜色。
用法:
<ff:SvgCachedImage Source="{ImageFromResource file_name.svg}" />
<ff:SvgCachedImage Source="{ImageFromResource Icons/file_name.svg}" />
<Image Source="{ImageFromResource file_name.png}" />
<Image Source="{ImageFromResource file_name.png, Assembly=MyAssembly}" />

ImageFromResourceExtension类:

using FFImageLoading.Svg.Forms;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;

/// <summary>
/// Get image source from assembly resource by using partial name.
/// </summary>
/// <example>
/// &lt;ff:SvgCachedImage Source="{ImageFromResource file_name.svg}" /&gt;
/// &lt;ff:SvgCachedImage Source="{ImageFromResource Icons/file_name.svg}" /&gt;
/// &lt;ff:Image Source="{ImageFromResource file_name.png}" /&gt;
/// &lt;ff:Image Source="{ImageFromResource file_name.png, Assembly=MyAssembly}" /&gt;
/// </example>
/// <remarks>
/// Parameter format without extension:
/// Source="resource://{AssemblyName}.{PathName}.{FileName}"
/// </remarks>
[ContentProperty(nameof(Source))]
public class ImageFromResourceExtension : IMarkupExtension
{

    public static Assembly DefaultAssembly = typeof(ImageResourceExtension).GetTypeInfo().Assembly;

    public string Source { get; set; }
    public string Assembly { get; set; }

    public object ProvideValue(IServiceProvider serviceProvider)
        => GetResourcePath(Source, Assembly);

    public static string GetResourcePath(string name, string assembly = null)
        => "resource://" + GetFullName(name, assembly);

    public static string GetFullName(string name, string assembly = null)
    {
        if (string.IsNullOrEmpty(name))
            return null;
        // Replace folder separators with dots.
        name = name.Replace('/', '.');
        // Use different assembly if specified.
        var asm = string.IsNullOrEmpty(assembly)
            ? DefaultAssembly
            : System.Reflection.Assembly.Load(assembly);
        // Find full name of the resource by partial name.
        var fullName = asm.GetManifestResourceNames()
            .FirstOrDefault(x => x.EndsWith("." + name));
        return fullName;
    }

    public static ImageSource GetImage(string name, string assembly = null, StringDictionaryCollection map = null)
    {
        var fullName = GetFullName(name);
        if (fullName == null)
            return null;
        // Use different assembly if specified.
        var asm = string.IsNullOrEmpty(assembly)
            ? DefaultAssembly
            : System.Reflection.Assembly.Load(assembly);
        // Return image source.
        return fullName.EndsWith(".svg", StringComparison.OrdinalIgnoreCase)
            ? SvgImageSource.FromResource(fullName, asm, replaceStringMap: map)
            : ImageSource.FromResource(fullName, asm);
    }

}

这是纯金!谢谢! - Cezar Wagenheimer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接