Usando recursos SVG no Xamarin

Ao desenvolver um aplicativo móvel, há muitos pontos a serem considerados. Essa é a escolha da tecnologia na qual ele será escrito e o desenvolvimento da arquitetura do aplicativo e, de fato, a escrita do código. Mais cedo ou mais tarde chega o momento em que a espinha dorsal da aplicação está lá, toda a lógica está escrita e a aplicação, em geral, funciona, mas ... não há aparência. Aqui vale a pena pensar nos recursos gráficos que serão utilizados, já que os gráficos são a maior parte do tamanho da montagem final, seja .apk no Android ou .ipa no iOS. Enormes assemblies são, em princípio, esperados para jogos móveis, mesmo agora do PlayMarket você às vezes tem que baixar volumes de dados de até 2 GB e é bom se você pode se conectar a Wi-Fi durante o download ou se a operadora móvel fornecer uma conexão ilimitada de alta velocidade.Mas para jogos isso é esperado, e um aplicativo de negócios desse tamanho involuntariamente levanta a questão “De onde vem isso?”. Uma das razões para o grande tamanho da montagem de um aplicativo de negócios pode ser um número significativo de ícones e imagens que precisam ser exibidos nele. E também não se esqueça que uma grande quantidade de gráficos afeta proporcionalmente o desempenho do aplicativo.



Ao criar o componente gráfico de um aplicativo, geralmente há um problema sério. Existem muitos dispositivos móveis, de relógios a tablets, e suas resoluções de tela são muito diferentes. Por causa disso, muitas vezes é necessário incluir recursos gráficos em uma montagem em arquivos separados para cada um dos tipos existentes. 5 cópias para Android e 3 para iOS. Isso afeta significativamente o tamanho da montagem final que você carregará na loja.



Nós iremos lhe dizer o que pode ser feito para não entrar em tal situação neste artigo.



Comparação de formatos PNG e SVG



A principal diferença entre os formatos PNG e SVG é que PNG é um formato de bitmap e SVG é um formato vetorial.



Um bitmap é uma grade de pixels em um monitor e é usado em qualquer lugar, sejam pequenos ícones ou grandes banners. Dentre as vantagens desse tipo de gráfico, destacam-se também:



  1. Os gráficos raster permitem criar desenhos de quase qualquer complexidade, sem perda perceptível no tamanho do arquivo;
  2. Se nenhum escalonamento de imagem for necessário, a velocidade de processamento de imagens complexas é muito alta;
  3. A representação de bitmap de imagens é natural para a maioria dos dispositivos de E / S.


No entanto, também existem desvantagens.



Por exemplo, um bitmap não pode ser dimensionado perfeitamente. Quando você amplia uma imagem pequena, a imagem "espuma" e você pode ver os pixels que a constituem.







Além disso, imagens simples compostas por um grande número de pontos são grandes. Portanto, é recomendável armazenar desenhos simples em formato vetorial. Todas as opções acima são verdadeiras para o formato PNG e qualquer outro formato de gráfico raster.

O formato SVG, por sua vez, não é realmente uma imagem. De acordo com o artigo da Wikipedia, SVG é uma linguagem de marcação de gráficos vetoriais escalonável que permite ler e editar um arquivo conforme necessário.



Além disso, por ser uma linguagem de marcação, o SVG permite que você aplique filtros em um documento (por exemplo, desfoque, extrusão, etc.). Eles são declarados como tags que o visualizador é responsável por renderizar, o que significa que não afetam o tamanho do arquivo original.



Além do acima, o formato SVG tem uma série de outras vantagens:



  1. Como formato vetorial, o SVG permite dimensionar qualquer parte de uma imagem sem perda de qualidade;
  2. Gráficos raster podem ser inseridos em um documento SVG;
  3. Integra-se facilmente com documentos HTML e XHTML.


No entanto, também existem desvantagens neste formato:



  1. Quanto mais detalhes precisos na imagem, mais rápido o tamanho dos dados SVG aumenta. Em alguns casos, o SVG não só não oferece vantagens, mas também perde para o raster;
  2. A complexidade de uso em aplicações cartográficas, pois para a correta visualização de uma pequena parte da imagem, é necessário ler todo o documento.


Há outra desvantagem quando se trata de desenvolver aplicativos móveis na plataforma Xamarin.



Para funcionar corretamente com este formato, você precisa conectar bibliotecas adicionais ou procurar soluções alternativas.



Trabalhando com formato SVG em Xamarin.Android



Conforme mencionado acima, o Xamarin não oferece suporte a SVG fora da caixa. Para resolver este problema - você pode usar bibliotecas de terceiros ou VectorDrawable. Recentemente, os desenvolvedores estão cada vez mais preferindo o último, uma vez que a maioria das bibliotecas para Xamarin são focadas no uso de plataforma cruzada no Xamarin.Forms e soluções para android nativo não são mais suportadas por seus desenvolvedores e estão desatualizadas, ou existem sérios problemas ao tentar construir com base biblioteca para Xamarin. Nesse sentido, vamos considerar o uso de VectorDrawable.



Para implementar essa abordagem, você precisará usar o Vector Asset Studio. Descobrir isso é fácil, você só precisa do Android Studio. Então, vamos começar:



  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.



Bastante trabalho preparatório que requer a instalação do Android Studio. Infelizmente, no momento em que este livro foi escrito, não foi possível encontrar conversores on-line funcionando corretamente. Alguns deram um erro ao tentar converter o arquivo SVG fornecido, alguns indicaram que era melhor usar o Vector Asset Studio.



De qualquer forma, conseguimos o arquivo necessário e agora podemos utilizá-lo em nosso projeto. Não descreveremos o processo de criação de um projeto Xamarin.Android, vamos direto ao ponto.

Primeiramente, colocamos o arquivo resultante na pasta drawable do projeto, então, como demonstração do trabalho com este arquivo, criamos 3 ImageViews na tela.



codifique aqui
<?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>




Na primeira ImageView, tentamos atribuir o arquivo SVG original na propriedade android: src, na segunda, o arquivo XML convertido na mesma propriedade e, na terceira, na propriedade app: srcCompat (observe que este namespace deve ser especificado conforme indicado no código )

Os resultados já eram perceptíveis no designer, antes de o aplicativo ser lançado - a única maneira segura de exibir corretamente nosso arquivo é fornecida no terceiro ImageView.





Agora você precisa se certificar de que a imagem é exibida corretamente em diferentes dispositivos. Para comparação, escolhemos Huawei Honor 20 Pro e Nexus 5. E também, em vez de métodos de exibição incorretos, especificamos o desejado e redimensionamos o ImageView para 150x150 dp, 200x200 dp e 300x300 dp.



Resultados do trabalho

Huawei Honor 20 Pro





Nexus 5







Como você pode ver, a qualidade das imagens é a mesma, o que significa que alcançamos o resultado desejado.



O arquivo resultante é usado a partir do código da mesma maneira que de costume

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



Trabalhando com formato SVG em Xamarin.iOS



No caso do Xamarin.iOS, a situação é a mesma que no Xamarin.Android, no sentido de que trabalhar com arquivos SVG não é suportado desde o início. No entanto, sua implementação não requer muito esforço. No caso de desenvolvimento nativo para iOS, o SVG requer que o SVGKit seja incluído. Ele permite que você processe esses arquivos sem recorrer a soluções de terceiros. No caso do Xamarin.iOS, podemos usar a biblioteca SVGKit.Binding . Este é um wrapper C # sobre o SVGKit original.



Tudo o que precisamos é conectar o pacote NuGet ao nosso projeto. No momento em que este artigo foi escrito, a versão mais recente é 1.0.4.





Infelizmente, aparentemente, esta biblioteca não é mais suportada, mas é bastante adequada para uso no projeto.

Aqui, a classe SVGKImage (a própria imagem SVG) e SVGKFastImageView (o controle para exibir tais imagens) são implementados.



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 criar um SVGKImage, a biblioteca implementa duas opções dependendo da BuildAction do arquivo - BundleResource (denotado por image_bundle_resource no código) e Content (denotado por image_content no código).

Infelizmente, a biblioteca tem uma série de desvantagens:



  1. SVGKFastImageView não oferece suporte à inicialização sem fornecer SVGKImage - um erro é lançado indicando a necessidade de usar o construtor fornecido no código;
  2. Não há como usar arquivos SVG em outros controles. No entanto, se isso não for necessário, você pode usá-lo.


Resultado do programa




Se o aplicativo for crítico para usar arquivos SVG não apenas no ImageView, você pode usar outras bibliotecas. Por exemplo, FFImageLoading . Esta é uma biblioteca poderosa que permite não apenas descarregar imagens SVG no UIImage Xamarin.iOS nativo, mas também fazer isso diretamente no controle desejado, economizando tempo de desenvolvimento. Também existe uma funcionalidade para baixar imagens da Internet, mas não a consideraremos neste artigo.



Para usar a biblioteca, você precisa conectar dois pacotes NuGet ao projeto - Xamarin.FFImageLoading e Xamarin.FFImageLoading.SVG.





No aplicativo de teste, usamos um método que carrega a imagem SVG diretamente no UIImageView e descarrega a imagem no UIImage nativo.



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




Também existe um método nesta biblioteca para substituir a representação de string SVG em UIImage, mas só faz sentido para arquivos pequenos.



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




A biblioteca também possui uma série de funcionalidades, mas não as consideraremos aqui. A única coisa que realmente vale a pena mencionar é que esta biblioteca pode ser usada em projetos Xamarin.Android também. Para uso em projetos Xamarin.Forms, existem análogos dessa biblioteca, que discutiremos a seguir.



Trabalhando com formato SVG em Xamarin.Forms



Em geral, não é necessário procurar bibliotecas para formulários, você pode simplesmente conectar as plataformas conhecidas aos projetos e é muito demorado e enfadonho reescrever renderizações para cada controle que deseja usar. Felizmente, há uma solução que compartilharemos.



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());
    }
    
Depois disso, a biblioteca pode ser usada.

A biblioteca implementa chamadas para recursos SVG localizados em projetos de plataforma e projetos PCL EmbeddedResouce. SvgCachedImage é usado para exibir imagens SVG. Ao contrário do controle de imagem original usado em Xamarin.Forms e aceitando um ImageSource, SvgCachedImage funciona com SvgImageSource.



IMPORTANTE!
Antes de usar o namespace svg mostrado abaixo, você deve declará-lo:



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




Você pode fornecê-lo de várias maneiras:



  1. Especifique no arquivo XAML o nome do arquivo SVG localizado nos recursos do projeto da plataforma:

    <svg:SvgCachedImage
                Source="question.svg"
                WidthRequest="100"
                HeightRequest="100"/>
    
  2. Especifique no arquivo XAML o caminho completo para o arquivo SVG que é um recurso incorporado no projeto PCL:



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


    Ao carregar de recursos incorporados, você pode especificar o nome de outro assembly:



    resource://SVGFormsTest.SVG.question1.svg?assembly=[ASSEMBLY FULL NAME]
    
  3. Ao trabalhar a partir do código, primeiro damos um nome aos controles:



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


    Então, dependendo de qual recurso está sendo usado, escolhemos uma das opções:



    • usar recursos embutidos

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



Os recursos SVG também apresentam uma pequena desvantagem. Eles não podem ser fornecidos como um ícone de aplicativo, uma vez que apenas arquivos PNG e JPEG podem ser usados ​​como um ícone de acordo com as diretrizes do Google e da Apple.




All Articles