Usar recursos SVG en Xamarin

Al desarrollar una aplicación móvil, hay muchos puntos a los que prestar atención. Ésta es la elección de la tecnología sobre la que se escribirá y el desarrollo de la arquitectura de la aplicación y, de hecho, la escritura del código. Tarde o temprano llega un momento en que la columna vertebral de la aplicación está ahí, toda la lógica está escrita y la aplicación, en general, funciona, pero ... no hay apariencia. Aquí vale la pena pensar en los recursos gráficos que se utilizarán, ya que los gráficos constituyen la mayor parte del tamaño del ensamblaje final, ya sea .apk en Android o .ipa en iOS. En principio, se esperan conjuntos enormes para juegos móviles, incluso ahora desde PlayMarket a veces tiene que descargar volúmenes de datos de hasta 2 GB y es bueno si puede conectarse a Wi-Fi durante la descarga o si el operador móvil proporciona una conexión ilimitada de alta velocidad.Pero para los juegos esto es lo esperado, y una aplicación empresarial de este tamaño plantea involuntariamente la pregunta "¿De dónde viene esto?". Una de las razones del gran tamaño del ensamblaje de una aplicación empresarial puede ser la gran cantidad de iconos e imágenes que deben mostrarse en ella. Y tampoco olvide que una gran cantidad de gráficos afecta proporcionalmente el rendimiento de la aplicación.



Al crear el componente gráfico de una aplicación, suele haber un problema grave. Hay una gran cantidad de dispositivos móviles, desde relojes hasta tabletas, y sus resoluciones de pantalla son muy diferentes. Debido a esto, a menudo es necesario incluir recursos gráficos en un ensamblaje en archivos separados para cada uno de los tipos existentes. 5 copias para Android y 3 para iOS. Esto afecta significativamente el tamaño del ensamblaje final que cargará en la tienda.



En este artículo le diremos qué se puede hacer para no meterse en tal situación.



Comparación de formatos PNG y SVG



La principal diferencia entre los formatos PNG y SVG es que PNG es un formato de mapa de bits y SVG es un formato vectorial.



Un mapa de bits es una cuadrícula de píxeles en un monitor y se usa en todas partes, ya sean iconos pequeños o pancartas enormes. Entre las ventajas de este tipo de gráficos, cabe destacar también:



  1. Los gráficos de trama le permiten crear dibujos de casi cualquier complejidad, sin una pérdida notable en el tamaño del archivo;
  2. Si no se requiere escalado de imagen, la velocidad de procesamiento de imágenes complejas es muy alta;
  3. La representación de imágenes en mapa de bits es natural para la mayoría de los dispositivos de E / S.


Sin embargo, también hay desventajas.



Por ejemplo, un mapa de bits no se puede escalar perfectamente. Cuando agranda una imagen pequeña, la imagen "hace espuma" y puede ver los píxeles que la componen.







Además, las imágenes simples que constan de una gran cantidad de puntos son grandes. Por tanto, se recomienda almacenar dibujos sencillos en formato vectorial. Todo lo anterior es válido tanto para el formato PNG como para cualquier otro formato de gráficos rasterizados.

El formato SVG, a su vez, no es realmente una imagen. Según el artículo de wikipedia, SVG es un lenguaje de marcado de gráficos vectoriales escalable que le permite leer y editar un archivo según sea necesario.



Además, al ser un lenguaje de marcado, SVG le permite aplicar filtros dentro de un documento (por ejemplo, desenfoque, extrusión, etc.). Se declaran como etiquetas que el espectador es responsable de representar, lo que significa que no afectan el tamaño del archivo original.



Además de lo anterior, el formato SVG tiene otras ventajas:



  1. Como formato vectorial, SVG le permite escalar cualquier parte de una imagen sin pérdida de calidad;
  2. Los gráficos de trama se pueden insertar en un documento SVG;
  3. Se integra fácilmente con documentos HTML y XHTML.


Sin embargo, también hay desventajas de este formato:



  1. Cuanto más fino sea el detalle de la imagen, más rápido aumentará el tamaño de los datos SVG. En algunos casos, SVG no solo no proporciona ventajas, sino que también pierde para el ráster;
  2. La complejidad de uso en aplicaciones cartográficas, ya que para la correcta visualización de una pequeña parte de la imagen, es necesario leer todo el documento.


Existe otra desventaja cuando se trata de desarrollar aplicaciones móviles en la plataforma Xamarin.



Para trabajar correctamente con este formato, debe conectar bibliotecas adicionales o buscar soluciones.



Trabajar con formato SVG en Xamarin.Android



Como se mencionó anteriormente, Xamarin no admite SVG de fábrica. Para resolver este problema, puede utilizar bibliotecas de terceros o VectorDrawable. Recientemente, los desarrolladores prefieren cada vez más lo último, ya que la mayoría de las bibliotecas para Xamarin se centran en el uso multiplataforma en Xamarin.Forms, y las soluciones para Android nativo ya no son compatibles con sus desarrolladores y están desactualizadas, o hay problemas graves al intentar construir sobre su base. biblioteca para Xamarin. En este sentido, aquí consideraremos usar VectorDrawable.



Para implementar este enfoque, deberá utilizar Vector Asset Studio. Encontrarlo es bastante fácil, solo necesitas Android Studio. Vamos a empezar:



  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.



Suficiente trabajo preparatorio que requiere la instalación de Android Studio. Desafortunadamente, en el momento de escribir este artículo, no pudimos encontrar convertidores en línea que funcionen correctamente. Algunos dieron un error al intentar convertir el archivo SVG proporcionado, algunos indicaron que era mejor usar Vector Asset Studio.



De todos modos, obtuvimos el archivo requerido y ahora podemos usarlo en nuestro proyecto. No describiremos el proceso de creación de un proyecto de Xamarin.Android, vayamos directamente al grano.

En primer lugar, colocamos el archivo resultante en la carpeta dibujable del proyecto, luego, como demostración de cómo trabajar con este archivo, creamos 3 ImageViews en la pantalla.



codificar aquí
<?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>




En el primer ImageView, intentamos asignar el archivo SVG original en la propiedad android: src, en el segundo, el archivo XML convertido en la misma propiedad, y en el tercero, en la propiedad app: srcCompat (tenga en cuenta que este espacio de nombres debe especificarse como se indica en el código ).

Los resultados ya eran notables en el diseñador, antes de que se lanzara la aplicación; la única forma segura de mostrar correctamente nuestro archivo se da en el tercer ImageView.





Ahora debe asegurarse de que la imagen se muestre correctamente en diferentes dispositivos. Para comparar, elegimos Huawei Honor 20 Pro y Nexus 5. Y también, en lugar de métodos de visualización incorrectos, especificamos el deseado y cambiamos el tamaño de ImageView a 150x150 dp, 200x200 dp y 300x300 dp.



Resultados del trabajo

Huawei Honor 20 Pro





Nexus 5







Como puede ver, la calidad de las imágenes es la misma, lo que significa que hemos logrado el resultado deseado.



El archivo resultante se usa a partir del código de la misma manera que de costumbre.

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



Trabajar con formato SVG en Xamarin.iOS



En el caso de Xamarin.iOS, la situación es la misma que con Xamarin.Android, en el sentido de que trabajar con archivos SVG no es compatible de forma inmediata. Sin embargo, su implementación no requiere mucho esfuerzo. En caso de desarrollo nativo de iOS, SVG requiere que se incluya SVGKit. Le permite procesar dichos archivos sin recurrir a soluciones de terceros. En el caso de Xamarin.iOS, podemos usar la biblioteca SVGKit.Binding . Este es un contenedor de C # sobre el SVGKit original.



Todo lo que necesitamos es conectar el paquete NuGet a nuestro proyecto. En el momento de escribir este artículo, la última versión es 1.0.4.





Desafortunadamente, aparentemente, esta biblioteca ya no es compatible, pero es bastante adecuada para su uso en el proyecto.

Aquí se implementan la clase SVGKImage (la propia imagen SVG) y SVGKFastImageView (el control para mostrar tales imágenes).



código para usar
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);
}


Para crear una SVGKImage, la biblioteca implementa dos opciones dependiendo de la BuildAction del archivo: BundleResource (denotado por image_bundle_resource en el código) y Content (denotado por image_content en el código).

Desafortunadamente, la biblioteca tiene una serie de desventajas:



  1. SVGKFastImageView no admite la inicialización sin proporcionar SVGKImage: se genera un error que indica la necesidad de utilizar el constructor proporcionado en el código;
  2. No hay forma de usar archivos SVG en otros controles. Sin embargo, si esto no es necesario, puede usarlo.


Resultado del programa




Si la aplicación es fundamental para usar archivos SVG no solo en ImageView, puede usar otras bibliotecas. Por ejemplo, FFImageLoading . Es una poderosa librería que te permite no solo descargar imágenes SVG en la UIImage nativa de Xamarin.iOS, sino también hacerlo directamente en el control deseado, ahorrando tiempo de desarrollo. También existe una funcionalidad para descargar imágenes de Internet, pero no la consideraremos en este artículo.



Para usar la biblioteca, debe conectar dos paquetes NuGet al proyecto: Xamarin.FFImageLoading y Xamarin.FFImageLoading.SVG.





En la aplicación de prueba, usamos un método que carga la imagen SVG en el UIImageView directamente y descarga la imagen en el UIImage nativo.



Código de muestra
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);
}




También hay un método en esta biblioteca para anular la representación de la cadena SVG en UIImage, pero solo tiene sentido para archivos pequeños.



Código de muestra
    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();




La biblioteca también tiene varias funcionalidades, pero no las consideraremos aquí. Lo único que realmente vale la pena mencionar es que esta biblioteca también se puede usar en proyectos de Xamarin.Android. Para su uso en proyectos de Xamarin.Forms, hay análogos de esta biblioteca, que analizaremos a continuación.



Trabajar con formato SVG en Xamarin.Forms



En general, no es necesario buscar bibliotecas para formularios, simplemente puede conectar las plataformas conocidas a los proyectos y tomar mucho tiempo y aburrido volver a escribir los renderizados para cada control que desee usar. Afortunadamente, hay una solución que compartiremos.



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());
    }
    
Después de eso, se puede usar la biblioteca.

La biblioteca implementa llamadas a recursos SVG ubicados tanto en proyectos de plataforma como en proyectos PCL EmbeddedResouce. SvgCachedImage se utiliza para mostrar imágenes SVG. A diferencia del control de imagen original que se usa en Xamarin.Forms y que acepta un ImageSource, SvgCachedImage funciona con SvgImageSource.



¡IMPORTANTE!
Antes de usar el espacio de nombres svg que se muestra a continuación, debe declararlo:



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




Puede proporcionarlo de varias formas:



  1. Especifique en el archivo XAML el nombre del archivo SVG ubicado en los recursos del proyecto de la plataforma:

    <svg:SvgCachedImage
                Source="question.svg"
                WidthRequest="100"
                HeightRequest="100"/>
    
  2. Especifique en el archivo XAML la ruta completa al archivo SVG que es un recurso incrustado en el proyecto PCL:



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


    Al cargar desde recursos incrustados, puede especificar el nombre de otro ensamblado:



    resource://SVGFormsTest.SVG.question1.svg?assembly=[ASSEMBLY FULL NAME]
    
  3. Cuando trabajamos desde código, primero le damos un nombre a los controles:



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


    Luego, dependiendo de qué recurso se esté utilizando, elegimos una de las opciones:



    • utilizar recursos integrados

      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, .



Los recursos SVG también tienen un pequeño inconveniente. No se pueden proporcionar como un ícono de aplicación, ya que solo los archivos PNG y JPEG se pueden usar como ícono de acuerdo con las pautas de Google y Apple.




All Articles