Utiliser des images vectorielles SVG dans Xamarin.Forms
Tags: svg, xamarinforms, xaml, french
Published: 2020-11-18 10:50:50

---
title: Utiliser des images vectorielles SVG dans Xamarin.Forms
published: true
date: 2020-11-17 14:55:28 UTC
tags: svg,XamarinForms,XAML,french
canonical_url: https://www.sylvainmoingeon.fr/utiliser-des-images-vectorielles-svg-dans-xamarinforms/
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/xv7cajmeqhfrorf6cxp7.png
---

Il est possible de longue date d'utiliser des bibliothèques tierces telles que [Skiasharp](https://github.com/mono/SkiaSharp) pour afficher des images vectorielles dans [Xamarin.Forms](https://www.sylvainmoingeon.fr/tags/xamarinforms/). Mais quand on est soucieux de la légèreté et des performances de son application, il est souvent préférable de se limiter aux fonctionnalités proposées par défaut par notre plateforme de développement.

Depuis l'apparition des `Path` avec la version 4.8, Xamarin.Forms est en mesure d'utiliser d'afficher des images vectorielles sans l'aide d'aucun autre package !

Je vous montre comment ça se path... euh... passe ?

* * *

## Convertir le contenu d'un SVG en Path 

> Les fonctionnalités utilisées dans cet article nécessitent Xamarin.Forms 5.0 ou au minimum Xamarin.Forms 4.8 avec le flag expérimental : `Device.SetFlags(new string[] { "Shapes_Experimental" });` dans le constructeur de la classe `App`

Alors oui, je vous ai un tout petit peu menti. On ne peut toujours pas incorporer un fichier svg et l'utiliser comme ressource. Mais un fichier svg n'étant que du texte balisé en XML, il est très facile d'en extraire le contenu et d'en faire une forme dans Xamarin.Form.

Nous prendrons deux exemples : un cas simple où l'image est constituée d'un seul chemin et un cas plus complexe où l'image est composée de plusieurs chemins.

Nous verrons ensuite comment rendre une image vectorielle réutilisable facilement dans le code sans duplication à l'aide des `Styles`.

### Image simple composée d'un seul chemin 

Nous allons partir de ce svg très simple représentant un avion :

![Une image vectorielle simple](https://www.sylvainmoingeon.fr/media/posts/39/airport.svg)<figcaption>Une image vectorielle simple</figcaption>

Si vous ouvrez le fichier avec un éditeur de texte, vous y trouverez ceci :

```xml
<?xml version="1.0" encoding="UTF-8"?>
<svg enable-background="new 0 0 64 64" version="1.1" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg">
    <path d="M15,6.8182L15,8.5l-6.5-1 l-0.3182,4.7727L11,14v1l-3.5-0.6818L4,15v-1l2.8182-1.7273L6.5,7.5L0,8.5V6.8182L6.5,4.5v-3c0,0,0-1.5,1-1.5s1,1.5,1,1.5v2.8182 L15,6.8182z"/>
</svg>

```

Ce qui nous intéresse ici, c'est la balise `path` et en particulier son attribut `d` contenant le tracé du dessin. Nous allons simplement copier le contenu de `d` dans la propriété `Data` d'un `Path` Xamarin.Forms. Comme ceci : 

```xml
<Path Aspect="Uniform"
      Data="M15,6.8182L15,8.5l-6.5-1 l-0.3182,4.7727L11,14v1l-3.5-0.6818L4,15v-1l2.8182-1.7273L6.5,7.5L0,8.5V6.8182L6.5,4.5v-3c0,0,0-1.5,1-1.5s1,1.5,1,1.5v2.8182 L15,6.8182z"
      Fill="Black"
      HeightRequest="64" />
```

La propriété `Aspect` avec la valeur `Uniform` conserve les proportions de l'image. La propriété `Fill` indique la couleur de remplissage de la forme.

Sans entrer trop loin dans les détails, il est très facile de manipuler l'image, par exemple en modifier le contour, le remplissage ou lui appliquer des transformations.

La même image vectorielle agrandie x2, pivotée de 45° avec un fond vert et un contour pointillé noir.

```xml
<Path Aspect="Uniform"
      Data="M15,6.8182L15,8.5l-6.5-1 l-0.3182,4.7727L11,14v1l-3.5-0.6818L4,15v-1l2.8182-1.7273L6.5,7.5L0,8.5V6.8182L6.5,4.5v-3c0,0,0-1.5,1-1.5s1,1.5,1,1.5v2.8182 L15,6.8182z"            
      Fill="Green"
      HeightRequest="64"
      Rotation="45"
      Stroke="Black"
      Scale="2"
      StrokeDashArray="2 1"
      StrokeThickness="2" />
```

Le résultat sous Android :

![Une image vectorielle, affichée et manipulée dans Xamarin.Forms](https://www.sylvainmoingeon.fr/media/posts/39/screenshot-svg-simple-2.png)<figcaption>Une image vectorielle, affichée et manipulée dans Xamarin.Forms</figcaption>

### Image complexe composée de plusieurs chemins 

Malheureusement, les images vectorielles ne sont pas toujours aussi simples et sont parfois composées de plusieurs chemins. Par exemple celle-ci :

![](https://www.sylvainmoingeon.fr/media/posts/39/car.svg)

```xml
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512">
    <path d="M104,320a24,24,0,1,0,24,24A24.028,24.028,0,0,0,104,320Zm0,32a8,8,0,1,1,8-8A8.009,8.009,0,0,1,104,352Z"/>
    <path d="M408,320a24,24,0,1,0,24,24A24.028,24.028,0,0,0,408,320Zm0,32a8,8,0,1,1,8-8A8.009,8.009,0,0,1,408,352Z"/>
    <path d="M488,304V256a48.051,48.051,0,0,0-48-48H373.54l-22-58.68A43.052,43.052,0,0,0,310.7,120H160a43.044,43.044,0,0,0-40.72,28.97L90.96,208H72a48.051,48.051,0,0,0-48,48v48A16.021,16.021,0,0,0,8,320v16a16.021,16.021,0,0,0,16,16H48.58a55.994,55.994,0,0,0,110.84,0H352.58a55.994,55.994,0,0,0,110.84,0H488a16.021,16.021,0,0,0,16-16V320A16.021,16.021,0,0,0,488,304ZM356.46,208H256V160h82.46ZM40,264H56v8H40Zm8.58,72H24V320H53.41A55.5,55.5,0,0,0,48.58,336ZM104,384a40,40,0,1,1,40-40A40.04,40.04,0,0,1,104,384Zm248.58-48H159.42a55.5,55.5,0,0,0-4.83-16H357.41A55.5,55.5,0,0,0,352.58,336ZM408,384a40,40,0,1,1,40-40A40.04,40.04,0,0,1,408,384Zm40-80a7.337,7.337,0,0,0-.81.05,55.871,55.871,0,0,0-78.37-.01A7.383,7.383,0,0,0,368,304H144a7.383,7.383,0,0,0-.82.04,55.871,55.871,0,0,0-78.37.01A7.337,7.337,0,0,0,64,304H40V288H64a8,8,0,0,0,8-8V256a8,8,0,0,0-8-8H41.01A32.058,32.058,0,0,1,72,224H96a8,8,0,0,0,7.21-4.54l30.71-64a7.5,7.5,0,0,0,.37-.93A27.079,27.079,0,0,1,160,136H310.7a27.027,27.027,0,0,1,19.22,8H160a8,8,0,0,0-8,8v64a8,8,0,0,0,8,8H440a32.058,32.058,0,0,1,30.99,24H448a8,8,0,0,0-8,8v24a8,8,0,0,0,8,8h24v16ZM240,160v48H168V160ZM472,264v8H456v-8Zm16,72H463.42a55.5,55.5,0,0,0-4.83-16H488Z"/>
    <path d="M256,248h40a8,8,0,0,0,0-16H256a8,8,0,0,0,0,16Z"/>
</svg>

```

Malheur ! l'image contient plusieurs chemins mais notre objet `Path` n'a qu'une seule propriété `Data` ! Comment faire ?

Heureusement, la propriété `Data` de notre `Path` peut contenir bien plus qu'une simple chaîne de caractère, notamment un groupe de géométrie. Nous allons donc créer un `GeometryGroup` contenant des `PathGeometry` dont nous renseigneront la propriété `Figures`.

Chaque path de notre svg alimente ainsi les propriétés `Figures` de nos `PathGeometry` :

```xml
<Path Aspect="Uniform"
      Fill="Black"
      HeightRequest="64">
    <Path.Data>
        <GeometryGroup>
            <PathGeometry Figures="M104,320a24,24,0,1,0,24,24A24.028,24.028,0,0,0,104,320Zm0,32a8,8,0,1,1,8-8A8.009,8.009,0,0,1,104,352Z" />
            <PathGeometry Figures="M408,320a24,24,0,1,0,24,24A24.028,24.028,0,0,0,408,320Zm0,32a8,8,0,1,1,8-8A8.009,8.009,0,0,1,408,352Z" />
            <PathGeometry Figures="M488,304V256a48.051,48.051,0,0,0-48-48H373.54l-22-58.68A43.052,43.052,0,0,0,310.7,120H160a43.044,43.044,0,0,0-40.72,28.97L90.96,208H72a48.051,48.051,0,0,0-48,48v48A16.021,16.021,0,0,0,8,320v16a16.021,16.021,0,0,0,16,16H48.58a55.994,55.994,0,0,0,110.84,0H352.58a55.994,55.994,0,0,0,110.84,0H488a16.021,16.021,0,0,0,16-16V320A16.021,16.021,0,0,0,488,304ZM356.46,208H256V160h82.46ZM40,264H56v8H40Zm8.58,72H24V320H53.41A55.5,55.5,0,0,0,48.58,336ZM104,384a40,40,0,1,1,40-40A40.04,40.04,0,0,1,104,384Zm248.58-48H159.42a55.5,55.5,0,0,0-4.83-16H357.41A55.5,55.5,0,0,0,352.58,336ZM408,384a40,40,0,1,1,40-40A40.04,40.04,0,0,1,408,384Zm40-80a7.337,7.337,0,0,0-.81.05,55.871,55.871,0,0,0-78.37-.01A7.383,7.383,0,0,0,368,304H144a7.383,7.383,0,0,0-.82.04,55.871,55.871,0,0,0-78.37.01A7.337,7.337,0,0,0,64,304H40V288H64a8,8,0,0,0,8-8V256a8,8,0,0,0-8-8H41.01A32.058,32.058,0,0,1,72,224H96a8,8,0,0,0,7.21-4.54l30.71-64a7.5,7.5,0,0,0,.37-.93A27.079,27.079,0,0,1,160,136H310.7a27.027,27.027,0,0,1,19.22,8H160a8,8,0,0,0-8,8v64a8,8,0,0,0,8,8H440a32.058,32.058,0,0,1,30.99,24H448a8,8,0,0,0-8,8v24a8,8,0,0,0,8,8h24v16ZM240,160v48H168V160ZM472,264v8H456v-8Zm16,72H463.42a55.5,55.5,0,0,0-4.83-16H488Z" />
            <PathGeometry Figures="M256,248h40a8,8,0,0,0,0-16H256a8,8,0,0,0,0,16Z" />
        </GeometryGroup>
    </Path.Data>
</Path>

```

Et hop :

![](https://www.sylvainmoingeon.fr/media/posts/39/screenshot-svg-complexe.png)

Nous voilà capable d'afficher des images vectorielles simples ou complexes directement dans Xamarin.Forms. Mais pour l'instant, cela reste fastidieux : pour utiliser une même image à plusieurs endroits, il reste nécessaire de copier-coller tout le contenu du `Path` à chaque fois. 

Voyons comment résoudre ce problème avec Style !

## Créer une image vectorielle réutilisable grâce aux styles 

Nous allons créer un `ResourceDictionary` pour y placer des `Styles` définissant le tracé de chaque image vectorielle.<resourcedictionary></resourcedictionary>

Toutes nos images SVG auront des propriétés communes, nous allons donc commencer par créer un style de base :

```xml
<Style x:Key="BaseSVGStyle" TargetType="Path">
    <Setter Property="Aspect" Value="Uniform" />
    <Setter Property="Fill" Value="Black" />
</Style>
```

Nous allons ensuite créer un style par image héritant de `BaseSVGStyle` à l'aide de la propriété `BasedOn`. Voici un exemple :

```xml
<Style x:Key="PlaneSVG"
        BasedOn="{StaticResource BaseSVGStyle}"
        TargetType="Path">
    <Setter Property="Data" Value="m430.37 48.711c29.15-29.153-11.17-67.267-39.96-38.479l-106.3 106.3-243.52-64.372-40.59 40.595 200.71 105.71-81.18 81.17-63.104-7.75-32.106 32.11 71.595 37.64 37.645 71.6 32.1-32.11-7.38-62.74 81.18-81.17 103.43 199.39 40.6-40.6-61.63-238.58 108.51-108.71z" />
    <Setter Property="HeightRequest" Value="64" />
</Style>
    
<Style x:Key="CarSVG"
        BasedOn="{StaticResource BaseSVGStyle}"
        TargetType="Path">
    <Setter Property="HeightRequest" Value="32" />
    <Setter Property="Data">
        <Setter.Value>
            <GeometryGroup>
                <PathGeometry Figures="M104,320a24,24,0,1,0,24,24A24.028,24.028,0,0,0,104,320Zm0,32a8,8,0,1,1,8-8A8.009,8.009,0,0,1,104,352Z" />
                <PathGeometry Figures="M408,320a24,24,0,1,0,24,24A24.028,24.028,0,0,0,408,320Zm0,32a8,8,0,1,1,8-8A8.009,8.009,0,0,1,408,352Z" />
                <PathGeometry Figures="M488,304V256a48.051,48.051,0,0,0-48-48H373.54l-22-58.68A43.052,43.052,0,0,0,310.7,120H160a43.044,43.044,0,0,0-40.72,28.97L90.96,208H72a48.051,48.051,0,0,0-48,48v48A16.021,16.021,0,0,0,8,320v16a16.021,16.021,0,0,0,16,16H48.58a55.994,55.994,0,0,0,110.84,0H352.58a55.994,55.994,0,0,0,110.84,0H488a16.021,16.021,0,0,0,16-16V320A16.021,16.021,0,0,0,488,304ZM356.46,208H256V160h82.46ZM40,264H56v8H40Zm8.58,72H24V320H53.41A55.5,55.5,0,0,0,48.58,336ZM104,384a40,40,0,1,1,40-40A40.04,40.04,0,0,1,104,384Zm248.58-48H159.42a55.5,55.5,0,0,0-4.83-16H357.41A55.5,55.5,0,0,0,352.58,336ZM408,384a40,40,0,1,1,40-40A40.04,40.04,0,0,1,408,384Zm40-80a7.337,7.337,0,0,0-.81.05,55.871,55.871,0,0,0-78.37-.01A7.383,7.383,0,0,0,368,304H144a7.383,7.383,0,0,0-.82.04,55.871,55.871,0,0,0-78.37.01A7.337,7.337,0,0,0,64,304H40V288H64a8,8,0,0,0,8-8V256a8,8,0,0,0-8-8H41.01A32.058,32.058,0,0,1,72,224H96a8,8,0,0,0,7.21-4.54l30.71-64a7.5,7.5,0,0,0,.37-.93A27.079,27.079,0,0,1,160,136H310.7a27.027,27.027,0,0,1,19.22,8H160a8,8,0,0,0-8,8v64a8,8,0,0,0,8,8H440a32.058,32.058,0,0,1,30.99,24H448a8,8,0,0,0-8,8v24a8,8,0,0,0,8,8h24v16ZM240,160v48H168V160ZM472,264v8H456v-8Zm16,72H463.42a55.5,55.5,0,0,0-4.83-16H488Z" />
                <PathGeometry Figures="M256,248h40a8,8,0,0,0,0-16H256a8,8,0,0,0,0,16Z" />
            </GeometryGroup>
        </Setter.Value>
    </Setter>
</Style>
```

Les styles consistent donc principalement à définir la valeur de la propriété `Data` de nos `Path`.

Pour les utiliser dans nos `Views`, nous devons d'abord déclarer le dictionnaire de ressource. Soit dans les ressources de la page, soit dans `App.xaml` si l'on souhaite accéder aux images partout dans le projet (_PathesStyles_ est le nom de mon dictionnaire de ressource).

```xml
<ContentPage.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <pathes:PathesStyles />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</ContentPage.Resources>
```

Ensuite, dans la contenu de la page, c'est simple comme _Bonjour_ , on applique le style souhaité à notre path :

```xml
<Path Style="{StaticResource CarSVG}" />
```

Il est toujours possible, bien entendu, de surcharger les valeurs proposées par le style. Pour afficher l'image en rouge par exemple : 

```xml
<Path Style="{StaticResource CarSVG}" Fill="Red" />
```

![Un florilège d'images vectorielles dans Xamarin.Forms](https://www.sylvainmoingeon.fr/media/posts/39/screenshot-svg.png)<figcaption>Un florilège d'images vectorielles dans Xamarin.Forms</figcaption>

Pour la démo, les valeurs sont en dur dans le code, mais bien entendu toutes les propriétés sont `Bindables` pour en modifier les valeurs à l'exécution. Votre créativité fera le reste !

## Projet GitHub 

Retrouvez la [démonstration de l'utilisation des Path Xamarin.Forms pour afficher des images vectorielles](https://github.com/SylvainMoingeon/SVGDemo) dans mon dépôt GitHub.

Pensez bien à liker et partager pour que ce soit utile au plus grand nombre !