Boutons personnalisés▲
Pour ne pas brusquer mes petits neurones et les vôtres (mais également parce que je pense que parler de sujets extrêmement techniques sur ce site implique que peu de lecteurs lisent et comprennent), je pense partir sur des choses assez basiques. Cet article simple et facile d'accès traite de la création de boutons personnalisés.
Une interface graphique consiste à établir un lien entre le programme et l'utilisateur. La communication peut bien sûr s'effectuer à sens unique, lorsque le programme affiche simplement des informations, mais on se rend vite compte qu'une interface à « sens unique » n'a que peu d'intérêt. Imaginez notre bon vieux Android dépourvu de boutons, autant dire que l'utilisation devient rapidement déplorable et ennuyante. La plupart des interfaces graphiques contiennent donc des éléments de type « bouton ». Le look 'n feel Android ne déroge pas à la règle et permet d'inclure des boutons dans les différents écrans de votre application.
Pour parfaire la « relation » entre l'interface et l'utilisateur, les boutons disposent en général de plusieurs états : normal, pressé, inactif, etc. L'utilisateur peut ainsi comprendre l'état d'un bouton suivant son image associée. Étudions, par exemple, le cas du bouton natif Android (dans sa version 1.6), sa couleur change suivant son état courant :
- lorsqu'il est inactif (disabled), il est gris clair ;
- lorsqu'il est actif, il est gris légèrement foncé ;
- lorsqu'il a le focus, il est orange vif ;
- lorsqu'il est pressé, il est orange clair ;
- etc.
Le développement d'un programme peut s'accompagner de la création d'un look 'n feel propre à la marque/personne qui réalise l'application. L'objectif de cet article est donc d'étudier comment modifier l'apparence native des boutons Android et de mieux comprendre le principe de fonctionnement de ces derniers.
L'objet Button hérite de TextView héritant lui-même de View. Il est donc possible d'accéder à l'attribut android:background de View et de le modifier afin de changer l'apparence native d'un bouton. Si vous effectuez cette opération (en modifiant simplement sa valeur à l'aide d'une image présente dans res/drawable, vous vous apercevrez que l'esthétique du bouton a bien changé, mais ne se modifie pas en fonction des différents états de ce dernier. L'astuce réside en fait dans l'objet « fourre-tout » (mais magnifiquement conçu) Drawable. Un Drawable est un objet pouvant « se dessiner ». Dans notre cas, il serait nécessaire d'avoir un Drawable qui change en fonction de l'état du bouton : un StateListDrawable !
StateListDrawable permet d'encapsuler plusieurs Drawables qui sont associés à un état (selected, focused, disabled, etc.). C'est grâce à ce type que nous allons pouvoir créer un bouton totalement personnalisé. Commençons tout d'abord par créer nos nouveaux boutons sous forme de 9-patchs (je ne pense pas avoir fait d'articles sur cette merveilleuse technique des 9-patchs – images extensibles – mais si certains lecteurs sont intéressés pour en savoir un peu plus, qu'ils n'hésitent pas à se manifester dans les commentaires) :
Il suffit maintenant de créer ce nouveau Drawable qui sera utilisé comme arrière-plan de notre bouton. Comme d'accoutumée, deux possibilités s'offrent à nous : la méthode code et la méthode XML. Assez partisan du « tout XML », je vous conseille d'utiliser cette méthode, car elle allège votre code et sépare bien la partie interface graphique de la partie métier. Le code d'exemple fourni plus bas montre une application utilisant les deux possibilités. En XML, on utilise simplement la balise selector dans laquelle on ajoute tous nos Drawables sous la forme de balises item. Pour finir, on choisit les différentes valeurs des attributs android:state et android:drawable qui permettent tout simplement d'associer le Drawable à un état (fichier mybutton.xml mis dans res/drawable) :
<?xml version="1.0" encoding="utf-8"?>
<selector
xmlns
:
android
=
"http://schemas.android.com/apk/res/android"
>
<item
android
:
state_window_focused
=
"false"
android
:
state_enabled
=
"true"
android
:
drawable
=
"@drawable/button1"
/>
<item
android
:
state_pressed
=
"true"
android
:
drawable
=
"@drawable/button2"
/>
<item
android
:
state_focused
=
"true"
android
:
drawable
=
"@drawable/button3"
/>
<item
android
:
state_enabled
=
"true"
android
:
drawable
=
"@drawable/button1"
/>
</selector>
Prenez garde à l'ordre des items dans la balise selector. En effet, lorsqu'on appuie sur le bouton, le système lit les lignes dans l'ordre pour déterminer quel Drawable utiliser. Lorsqu'on appuie sur un bouton, ce dernier est à la fois « pressed » et « enabled ». Si la ligne de l'état « enabled » avait été placée avant la ligne de l'état « pressed », dans l'exemple ci-dessus, le bouton n'aurait pas changé d'apparence, car l'état « enabled » aurait été considéré comme viable par le système et donc utilisé en premier.
Cela peut sembler bizarre, mais nous venons bien de créer un nouveau Drawable, c'est-à-dire un objet « dessinable » à partir d'un fichier XML/texte. La dernière étape consiste donc à modifier la propriété android:background de notre Button pour que ce dernier change totalement d'apparence. Encore une fois, cette action s'effectue plus facilement via le XML :
<Button
android
:
layout_width
=
"wrap_content"
android
:
layout_height
=
"wrap_content"
android
:
text
=
"New dummy content"
android
:
background
=
"@drawable/mybutton"
/>
Nous ne venons que d'effleurer les possibilités données par le package android.graphics.drawable. En effet, des objets comme LevelListDrawable, NinePatchDrawable (mon préféré) ou AnimationDrawable facilitent grandement l'utilisation des images sous Android. Pour bien montrer à quoi ressemblent les boutons créés, j'ai développé une petite application d'exemple disponible ici :
Remerciements▲
Un grand merci à jacques_jean pour sa relecture.