Loupe

Android : faire un splashscreen multi-résolutions, multi densités de pixels et éventuellement étendu.

Le splashscreen est le premier écran que voit votre utilisateur en lançant votre application. Souvent il s'agit du logo de l'application centré sur un fond uni correspondant à une couleur d'accentuation. Le problème rencontré ici c'est que les différents téléphones Android ont des densités de pixels différentes et des tailles d'écran différentes. En prenant simplement une image que l'on demande d'agrandir, on aura un affichage déformé, flou et dans tous les cas pas très propre. Dans cet article nous verrons la méthode que j'utilise pour faire un splashscreen multi-résolutions, multi densités de pixels et éventuellement étendu. Ces techniques ne s'appliquent pas nécessairement qu'à Xamarin.

 

ATTENTION : cet article contient des images pouvant choquer des designers sensibles. 

 

TL;DR

  • Définissez un style pour votre activité mettant une image comme fond d'écran.
  • Fournissez une image par densité de pixel.
  • Fournissez vos images au format 9 patch.

 

 Gérer les différentes densités de pixel

Vous le savez sûrement, Android gère 6 densités de pixels (le nombre de pixel que l'on arrive à mettre dans un pouce-carré) différentes. Plus la densité de pixels est élevée, plus l'affichage sera net et précis :

  • ldpi   à partir de 120dpi
  • mdpi  à partir de 160dpi
  • hdpi  à partir de 240dpi
  • xhdpi à partir de 320dpi
  • xxhdpi  à partir de 480dpi
  • xxxhdpi   à partir de 640dpi

 

La bonne pratique consiste donc à fournir une image par densité de pixel : cela permet de contrôler vous-même le rendu qu'aura votre image sur les différents écrans. Cela implique aussi de meilleures performances car cela évite au téléphone d'avoir à downscaler ou upscaler votre image à la volée.

Nous allons alors devoir fournir notre logo dans différentes densités de pixels. Je partirais du logo ci-dessous d'une dimension de 416x416 pixels que j'utiliserai pour la densité "ldpi". Cet image possède donc un logo centré et une couleur de fond déjà présente (on ne contrôle pas toujours ce que l'on nous donne).

splash.9.png

Voici ensuite les tailles que j'utiliserai par densité de pixel :

  • ldpi : 208x208 pixels
  • mdpi : 277x277 pixels
  • hdpi : 416x416 pixels
  • xhdpi : 624x624 pixels
  • xxhdpi : 832x832 pixels
  • xxxhdpi :1040x1040 pixels

Ces images utiliseront toutes le même nom et sont à placer dans les dossiers "Resources\drawable-xxx", xxx étant à remplacer par la densité de pixels ciblée. Vous remarquerez aussi la présence d'un dossier "drawable-nodpi" dans lequel je place les images que je ne souhaite pas voir upscaler/downscaler par Android et éviter ainsi des dépassements de mémoire et donc des crashes.

 android xamarin splashscreen les différentes densité de pixel

 

Définir un splashcreen

La définition d'un splashcreen consiste à créer une activité la plus simple possible (afin d'être chargée rapidement) à laquelle nous appliquerons un style personnalisé pour mettre notre logo en fond d'écran.

 

Pour définir un style de lancement, il faut créer un fichier xml et définir une balise "style" à laquelle nous donnerons un nom ("ThemeCompat.Splash" par exemple). Ce style dérivera d'un style de la librairie de Support Android afin de ne pas avoir de barre d'action : style/Theme.AppCompat.Light.NoActionBar. Il aura aussi comme effet d'appliquer l'image "splash.png" comme fond de la fenêtre/activité. 

<style name="ThemeCompat.Splash"
       parent="@style/Theme.AppCompat.Light.NoActionBar">
  
  <!--on utilise l'image "splash" (9patch) comme fond de page-->
  <item name="android:windowBackground">@drawable/splash</item>
  <item name="windowNoTitle">true</item>
  
  <!--splash en plein écran-->
  <item name="android:windowFullscreen">true</item>
  
   <!--pas de status bar-->
  <item name="android:windowContentOverlay">@null</item>
  
  <!--pas d'anim quand on passe du normal à l'étendu-->
  <item name="android:windowAnimationStyle">@null</item>
</style>

 

Vous remarquerez que je spécifie un "windowAnimationStyle" à null. Cela permet de supprimer l'animation lors du passage à l'activité suivante. Cela est pratique lorsque vous spécifiez un splashcreen étendu (un écran de votre application où vous pouvez faire un traitement plus long que le délai maximum imposé par les OS) car vous n'aurez pas d'effet visuel étrange en passant d'un écran à l'autre.

 

Le style est ensuite appliqué à une activité Android via un attribut (mais cela serait possible dans votre manifest xml à la main aussi). Cette activité ne charge pas de layout toujours pour être chargée au plus vite.

[Activity(
     MainLauncher = true
    , Icon = "@drawable/icon"
    , Theme = "@style/ThemeCompat.Splash")]

public class SplashScreen : AppCompatActivity
{
 protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);
        }
}

 

Gestion des différentes tailles d'écran

Le splashscreen est donc en place mais en fonction des tailles d'écrans il sera maheureusement déformé car l'image est étirée pour remplir l'écran. On pourrait se dire qu'il suffit de mettre une image au bon ratio mais ce n'est pas une méthode fiable car les tailles des écrans peuvent varier énormément en fonction du device (téléphone, tablette, télévision, montre, etc.)  mais aussi de l'orientation (paysage ou portrait de celui-ci). Il faut que notre logo soit centré dans l'écran mais qu'il ne soit pas déformé. 

splash.deformed.png

Pour cela nous allons créer une image PNG au format 9 Patch. Un PNG dans ce format possède une l'extension "9.png" et contient une bordure d'un pixel utilisée pour définir des règles d'utilisation de l'image. Une image de 400x400 pixels dans ce format n'aura donc que 398x398 pixels correspondant à l'image à afficher.

 

Les bordures haute et gauche permettent de définir les règles d'étirement de l'image :

  • Un pixel noir (il faut un noir absolu pour que cela soit pris en compte) correspond à un pixel qui peut être répliqué pour étirer l'image dans la taille finale.
  • Un pixel d'une autre couleur correspond à un pixel (et plus précisément une ligne ou une colonne) qui doit rester intact.

 

Les bordures basses et droites permettent de définir les règles de remplissage de l'image, par exemple pour les vues de type bouton. 

  • Un pixel noir correspond à un pixel qui peut servir pour placer le contenu.
  • Un pixel d'une autre couleur correspond à un pixel qui doit rester vide de contenu.

Google a aussi écrit une documentation expliquant ce format et sa mise en pratique pour les fonds servant à définir les boutons.

 

Dans notre cas, nous allons donc pouvoir indiquer que les lignes/colonnes complétement oranges peuvent être répliquées mais que les zones contenant le logo doivent rester non-répliquées pour préserver son affichage. Il n'est pas nécessaire de renseigner les parties droites et basses car on ne place pas de contenu dans ce contexte:

  • On agrandit l'image pour la passer à la taille 418x418 afin de laisser une bordure transparente. J'utilise paint.net qui le fait très bien agrandissant la zone de dessin après avoir chosir une couleur primaire transparente.
  • On dessine les pixels noir que l'on veut garder en haut et en bas. 
  • On laisse les pixels des extrémités en transparent.
  • On recommence l'opération pour toutes les densités de pixels. Ce processus étant un peu fastidieux, Android Studio possède un outil pour vous faciliter la vie.

Voici ainsi l'image finale que nous utiliserons à côté d'une image où j'ai volontairement forcé le trait des pixels noirs :

 etendu.png

 

 

 

Photo de profil

Ces billets pourraient aussi vous intéresser

Vous nous direz ?!

Commentaires

comments powered by Disqus