在Xamarin中使用SVG资源

在开发移动应用程序时,有很多注意事项。这是对其进行编写的技术,应用程序体系结构的开发以及实际上是代码的选择。迟早会有应用程序的核心出现,所有逻辑都已编写,并且该应用程序通常都可以运行,但是……没有外观。这里值得考虑将要使用的图形资源,因为图形占最终装配体大小的大部分,无论是Android上的.apk还是iOS上的.ipa。从原理上讲,移动游戏需要巨大的装配体,即使现在从PlayMarket有时也需要下载高达2 GB的数据量,如果您可以在下载过程中连接到Wi-Fi或移动运营商提供高速无限制的连接,那将是一个很好的选择。但是对于游戏来说,这是预料之中的,如此规模的商业应用会不由自主地提出一个问题:“这是从哪里来的?”。业务应用程序程序集很大的原因之一可能是必须在其中显示的大量图标和图片。同样不要忘记,大量的图形会成比例地影响应用程序的性能。



创建应用程序的图形组件时,通常会遇到严重的问题。从手表到平板电脑,移动设备种类繁多,其屏幕分辨率也大不相同。因此,对于每个现有类型,通常有必要在单独的文件中的程序集中包含图形资源。适用于Android的5个副本和适用于iOS的3个副本。这将极大地影响您将上载到商店的最终装配的大小。



在本文中,我们将告诉您可以采取什么措施来避免出现这种情况。



PNG和SVG格式的比较



PNG和SVG格式之间的主要区别在于PNG是位图格式,而SVG是矢量格式。



位图是监视器上的像素网格,在任何地方都可以使用,无论是小图标还是大横幅。在此类图形的优点中,还应注意以下几点:



  1. 光栅图形使您可以创建几乎任何复杂的图形,而不会造成文件大小的重大损失。
  2. 如果不需要图像缩放,则复杂图像的处理速度非常高。
  3. 图像的位图表示对于大多数I / O设备而言都是很自然的。


但是,也有缺点。



例如,位图不能完美缩放。放大小图片时,图像会“起泡”,并且可以看到其组成的像素。







此外,由大量点组成的简单图像也很大。因此,建议以矢量格式存储简单图形。对于PNG格式和任何其他栅格图形格式,以上所有内容均适用。

SVG格式实际上不是图像。根据Wikipedia的文章, SVG是一种可伸缩的矢量图形标记语言,可让您根据需要读取和编辑文件。



另外,作为一种标记语言,SVG允许您在文档中应用过滤器(例如模糊,凹凸等)。它们被声明为查看器负责渲染的标签,这意味着它们不影响原始文件的大小。



除上述内容外,SVG格式还具有许多其他优点:



  1. 作为矢量格式,SVG允许您缩放图像的任何部分而不会降低质量。
  2. 光栅图形可以插入到SVG文档中。
  3. 轻松与HTML和XHTML文档集成。


但是,这种格式有一些缺点:



  1. 图像中的细节越精细,SVG数据的大小增长越快。在某些情况下,SVG不仅不能提供优势,而且还会失去栅格。
  2. 制图应用程序的使用很复杂,因为要正确显示图像的一小部分,您需要阅读整个文档。


在Xamarin平台上开发移动应用程序时,还有另一个缺点。



要正确使用此格式,您需要连接其他库,或寻找解决方法。



在Xamarin.Android中使用SVG格式



如上所述,Xamarin不支持现成的SVG。要解决此问题-您可以使用第三方库或VectorDrawable。最近,开发人员越来越喜欢后者,因为Xamarin的大多数库都专注于Xamarin.Forms的跨平台使用,并且本机android的解决方案不再受其开发人员的支持并且已过时,或者在尝试基于它们进行构建时存在严重问题Xamarin的库。在这方面,我们将考虑使用VectorDrawable。



要实现此方法,您将需要使用Vector Asset Studio。找到它很容易,您只需要Android Studio。因此,让我们开始:



  1. Android Studio File -> New -> New Project;

    , — Vector Asset Studio, .
  2. drawable -> New -> Vector Asset;



    Asset Studio. Material Design, SVG PSD, xml-. .
  3. Asset Studio



    ,  , .
  4. Next 



    Xamarin.Android.



足够的准备工作,需要安装Android Studio。不幸的是,在撰写本文时,我们找不到能正常工作的在线转换器。某些人在尝试转换提供的SVG文件时出错,一些人指出使用Vector Asset Studio更好。



尽管如此,我们已经收到了所需的文件,现在可以在项目中使用它了。我们将不描述创建Xamarin.Android项目的过程,让我们直接讲一下。

首先,我们将结果文件放置在项目的drawable文件夹中,然后,作为使用此文件的演示,我们在屏幕上创建了3个ImageViews。



这里的代码
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
	xmlns:android        ="http://schemas.android.com/apk/res/android"
	xmlns:app            ="http://schemas.android.com/apk/res-auto"
	android:layout_width ="match_parent"
	android:layout_height="match_parent"
	android:minWidth="25px"
	android:minHeight="25px">
	<ImageView
		android:layout_width="150dp"
		android:layout_height="150dp"
		android:layout_alignParentLeft="true"
		android:id="@+id/imageView1"
		android:adjustViewBounds="true"
		app:srcCompat="@drawable/question_svg"
		android:background="@android:color/holo_red_dark"/>
	<ImageView
		android:layout_width="150dp"
		android:layout_height="150dp"
		android:layout_alignParentRight="true"
		android:id="@+id/imageView2"
		android:adjustViewBounds="true"
		app:src="@drawable/question"
		android:background="@android:color/holo_red_dark"/>
	<ImageView
		android:layout_width="150dp"
		android:layout_height="150dp"
		android:id="@+id/imageView3"
		android:adjustViewBounds="true"
		android:layout_marginTop="30dp"
		app:srcCompat="@drawable/question"
		android:layout_below="@id/imageView1"/>
</RelativeLayout>




在第一个ImageView中,我们尝试在android:src属性中分配原始SVG文件,在第二个中,在相同属性中分配转换后的XML文件,在第三个中,在app:srcCompat属性中分配原始SVG文件(请注意,必须按照代码中的指定指定此命名空间)。

在启动应用程序之前,结果在设计器中已经很明显-正确显示我们文件的唯一确定方法是在第三个ImageView中给出。





现在,您需要确保图像在其他设备上正确显示。为了进行比较,我们选择了Huawei Honor 20 Pro和Nexus5。此外,我们指定了一种合适的显示方式,并将ImageView的尺寸调整为150x150 dp,200x200 dp和300x300 dp,而不是错误的显示方法。



工作成果

Huawei Honor 20 Pro





Nexus 5







如您所见,图像的质量是相同的,这意味着我们已经达到了预期的结果。



代码中的生成文件与往常一样使用

image.SetImageResource(Resource.Drawable.< >);



在Xamarin.iOS中使用SVG格式



就Xamarin.iOS而言,情况与Xamarin.Android相同,这意味着不支持立即使用SVG文件。但是,其实现不需要太多的努力。如果是本机iOS开发,则SVG需要包含SVGKit。它允许您处理此类文件而无需借助第三方解决方案。对于Xamarin.iOS,我们可以使用SVGKit.Binding这是原始SVGKit的C#包装器。



我们所需要做的就是将NuGet包连接到我们的项目。在撰写本文时,最新版本为1.0.4。





不幸的是,显然不再支持该库,但是它非常适合在项目中使用。

在这里,实现了SVGKImage类(SVG图像本身)和SVGKFastImageView类(用于显示此类图像的控件)。



使用的代码
void CreateControls()
{
	var image_bundle_resource = new SVGKImage("SVGImages/question.svg");
	img1 = new SVGKFastImageView(image_bundle_resource);
	Add(img1);
	img1.Frame = new CGRect(View.Frame.Width / 4, 50, View.Frame.Width / 2, View.Frame.Width / 2);

	var image_content = new SVGKImage(Path.Combine(NSBundle.MainBundle.BundlePath, "SVGImages/question1.svg"));
	img2 = new SVGKFastImageView(image_content);
	Add(img2);
	img2.Frame = new CGRect(5, img1.Frame.Bottom + 5, View.Frame.Width - 5, View.Frame.Width - 5);
}


要创建SVGKImage,该库根据BuildAction文件实现两个选项-BundleResource(在代码中以image_bundle_resource表示)和Content(在代码中以image_content表示)。

不幸的是,该图书馆有许多缺点:



  1. SVGKFastImageView在不提供SVGKImage的情况下不支持初始化-抛出错误,表明需要使用代码中提供的构造函数;
  2. 无法在其他控件中使用SVG文件。但是,如果没有必要,则可以使用它。


计划成果




如果应用程序对于不仅在ImageView中使用SVG文件至关重要,还可以使用其他库。例如,FFImageLoading这是一个功能强大的库,它不仅使您可以在本机Xamarin.iOS UIImage中卸载SVG图像,而且还可以直接在所需控件中进行操作,从而节省了开发时间。还有从Internet下载图像的功能,但是我们在本文中不会考虑。



要使用该库,您需要将两个NuGet程序包连接到项目-Xamarin.FFImageLoading和Xamarin.FFImageLoading.SVG。





在我们的测试应用程序中,我们使用了一种将SVG图像直接加载到UIImageView并将图像卸载到本机UIImage的方法。



样例代码
private async Task CreateControls()
{
    img1 = new UIImageView();
    Add(img1);
    img1.Frame = new CGRect(View.Frame.Width / 4, 50, View.Frame.Width/2, View.Frame.Width/2);

    ImageService.Instance
                .LoadFile("SVGImages/question.svg")
                .WithCustomDataResolver(new SvgDataResolver((int)img1.Frame.Width, 0, true))
                .Into(img1);

    var button = new UIButton() { BackgroundColor = UIColor.Red};
    Add(button);
    button.Frame = new CGRect(View.Frame.Width/2 - 25, img1.Frame.Bottom + 20, 50, 50);

    UIImage imageSVG = await ImageService.Instance
                .LoadFile("SVGImages/question.svg")
                .WithCustomDataResolver(new SvgDataResolver((int)View.Frame.Width, 0, true))
                .AsUIImageAsync();
    if(imageSVG != null)
        button.SetBackgroundImage(imageSVG, UIControlState.Normal);
}




该库中还有一个方法可以覆盖UIImage中的SVG字符串表示形式,但仅对小文件有意义。



样例代码
    var svgString = @"<svg><rect width=""30"" height=""30"" style=""fill:blue"" /></svg>";

    UIImage img = await ImageService.Instance
		.LoadString(svgString)
		.WithCustomDataResolver(new SvgDataResolver(64, 0, true))
		.AsUIImageAsync();




该库还具有许多功能,但是在这里我们将不考虑它们。真正值得一提的唯一事情是该库也可以在Xamarin.Android项目中使用。为了在Xamarin.Forms项目中使用,该库有一些类似物,我们将在下面讨论。



在Xamarin.Forms中使用SVG格式



总的来说,不必寻找表单的库,您可以简单地连接项目已知的平台,并且需要很长时间和繁琐的时间来重写要使用的每个控件的渲染。幸运的是,我们将分享一种解决方案。



Xamarin.FFImageLoading Xamarin.FFImageLoading.SVG, Xamarin.Forms (Xamarin.FFImageLoading.Forms Xamarin.FFImageLoading.SVG.Forms). Xamarin.Forms , , :



  1. (PCL ) NuGet- — Xamarin.FFImageLoading.Forms Xamarin.FFImageLoading.SVG.Forms;
  2. AppDelegate.cs iOS-:

    public override bool FinishedLaunching( UIApplication app, NSDictionary options )
    {
        global::Xamarin.Forms.Forms.Init();
        FFImageLoading.Forms.Platform.CachedImageRenderer.Init();
        CachedImageRenderer.InitImageSourceHandler();
        var ignore = typeof(SvgCachedImage);
        LoadApplication(new App());
        return base.FinishedLaunching(app, options);
    }
  3. MainActivity.cs Android-:

    protected override void OnCreate( Bundle savedInstanceState )
    {
        TabLayoutResource = Resource.Layout.Tabbar;
        ToolbarResource = Resource.Layout.Toolbar;
        base.OnCreate(savedInstanceState);
    
        Xamarin.Essentials.Platform.Init(this, savedInstanceState);
        global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
        FFImageLoading.Forms.Platform.CachedImageRenderer.Init(true);
        CachedImageRenderer.InitImageViewHandler();
        var ignore = typeof(SvgCachedImage);
        LoadApplication(new App());
    }
    
之后,可以使用该库。

该库实现对平台项目和EmbeddedResouce PCL项目中的SVG资源的调用。SvgCachedImage用于显示SVG图像。与Xamarin.Forms中使用的原始Image控件和接受ImageSource不同,SvgCachedImage与SvgImageSource一起使用。



重要!
svg, , :



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




您可以通过几种方式提供它:



  1. 在XAML文件中指定位于平台项目资源中的SVG文件的名称:

    <svg:SvgCachedImage
                Source="question.svg"
                WidthRequest="100"
                HeightRequest="100"/>
    
  2. 在XAML文件中指定SVG文件的完整路径,该文件是PCL项目中的嵌入式资源:



    <svg:SvgCachedImage
                Source="resource://SVGFormsTest.SVG.question1.svg"
                WidthRequest="100"
                HeightRequest="100"/>
    


    从嵌入式资源加载时,可以指定另一个程序集的名称:



    resource://SVGFormsTest.SVG.question1.svg?assembly=[ASSEMBLY FULL NAME]
    
  3. 使用代码工作时,我们首先为控件命名:



    <svg:SvgCachedImage
                x:Name="image"
                WidthRequest="100"
                HeightRequest="100"/>
    


    然后,根据所使用的资源,我们选择以下选项之一:



    • 使用嵌入式资源

      image.Source = SvgImageSource.FromResource("SVGFormsTest.SVG.question1.svg");






    • image.Source = SvgImageSource.FromFile("question.svg");


  4. Binding 2 :



    • , SvgImageSource. , XAML- :



      <svg:SvgCachedImage
                  Source="{Binding Source}"
                  WidthRequest="100"
                  HeightRequest="100"/>
      
    • . , . :



      <ContentPage.Resources>
              <ResourceDictionary>
                  <svg:SvgImageSourceConverter
                      x:Key="SourceConverter"/>
              </ResourceDictionary>
          </ContentPage.Resources>
      


      :



      <svg:SvgCachedImage
                  Source="{Binding Source1, Converter={StaticResource SourceConverter}}"
                  WidthRequest="100"
                  HeightRequest="100"/>
      


      :



      public MainVM()
      {
          source1 = "question.svg";
      }
      
      string source1;
      public string Source1
      {
          get => source1;
          set
          {
              source1 = value;
          }
      }
      


      :



      public MainVM()
      {
          source1 = "resource://SVGFormsTest.SVG.question1.svg";
      }
      
      string source1;
      public string Source1
      {
          get => source1;
          set
          {
              source1 = value;
          }
      }
      


      , . , , .




SVG- , . , , , , , , SVG- . , PNG- , SVG, .



SVG资源也有一个小缺点。它们不能作为应用程序图标提供,因为根据Google和Apple准则,只有PNG和JPEG文件可以用作图标。




All Articles