【问题标题】:Xamarin.Forms set Button ImageSource as ffimageloading Svg embedded resourceXamarin.Forms 将 Button ImageSource 设置为 ffimageloading Svg 嵌入资源
【发布时间】:2020-04-01 13:58:01
【问题描述】:

我会在 Xamarin.Forms 中将 svg 嵌入图像作为 ImageSource 放入 Button,类似这样

<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}}"

有什么帮助吗? 谢谢

【问题讨论】:

标签: svg xamarin.forms ffimageloading


【解决方案1】:

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

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

用法:使用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"

更新:我们可以使用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
  • 我没有找到作为图像源加载的方法,但我们可以制作一个自定义控件来加载自定义控件。我已经更新了我的回复。
【解决方案2】:

更新了 Xamarin 的原始图像资源扩展类。 OP 的课程有两个问题:

  1. 缺少允许跳过“源”属性名称的 ContentProperty 属性。
  2. 部分资源名称转换为完整资源名称的部分。

添加了可选的“Assembly”属性,允许指定不同的程序集。

用法:

<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 类:

/// <summary>
/// Get image source from assembly resource by using partial name.
/// </summary>
/// <example>
/// &lt;ff:SvgCachedImage Source="{ImageFromResource file_name.svg}" /&gt;
/// &lt;Image Source="{ImageFromResource file_name.png}" /&gt;
/// &lt;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
{

    private static Assembly defaultAssembly = typeof(ImageResourceExtension).GetTypeInfo().Assembly;

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

    public object ProvideValue(IServiceProvider serviceProvider)
    {
        if (string.IsNullOrEmpty(Source))
            return null;
        // Replace folder separators with dots.
        var name = Source.Replace('/', '.');
        // Find full name of the resource by partial name.
        var fullName = defaultAssembly.GetManifestResourceNames()
            .FirstOrDefault(x => x.EndsWith("." + name));
        if (fullName == null)
            return null;
        // Load different assembly if specified.
        var assembly = string.IsNullOrEmpty(Assembly)
            ? defaultAssembly
            : System.Reflection.Assembly.Load(Assembly);
        // Return image source.
        return name.EndsWith(".svg", StringComparison.OrdinalIgnoreCase)
            ? SvgImageSource.FromResource(fullName, assembly)
            : ImageSource.FromResource(fullName, assembly);
    }
}

【讨论】:

    猜你喜欢
    • 2018-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-24
    • 1970-01-01
    • 2021-07-10
    • 1970-01-01
    相关资源
    最近更新 更多