5. Introduction
C’est quoi un Drawable?
• Entité qui peut être « dessinée »
• Une forme, un gradient, une image, un 9-
patch, etc.
4
6. Introduction
C’est quoi un Drawable?
• Entité qui peut être « dessinée »
• Une forme, un gradient, une image, un 9-
patch, etc.
• Composant essentiel du SDK Android
4
7. Introduction
C’est quoi un Drawable?
• Entité qui peut être « dessinée »
• Une forme, un gradient, une image, un 9-
patch, etc.
• Composant essentiel du SDK Android
• Instanciable en Java ou XML
4
8. Introduction
Pourquoi est-ce si important?
• Gestion du multi-device facilitée
• Abstraction de ce qui est « dessinable »
• Plus simple d’utilisation
• Plus évolué que les Bitmaps !
• Possibilité de modifier des widgets
sans les étendre
5
16. « How-to » basique
Gné ? Ça marche pas !
• Mon Canvas n’est pas dans un état «
acceptable » ?
9
17. « How-to » basique
Gné ? Ça marche pas !
• Mon Canvas n’est pas dans un état «
acceptable » ?
• J’ai oublié de mettre la vue dans mon
layout ?
9
18. « How-to » basique
Gné ? Ça marche pas !
• Mon Canvas n’est pas dans un état «
acceptable » ?
• J’ai oublié de mettre la vue dans mon
layout ?
• .... Je n’ai pas définit la taille de mon
Drawable
9
19. « How-to » basique
Gné ? Ça marche pas !
• Mon Canvas n’est pas dans un état «
acceptable » ?
• J’ai oublié de mettre la vue dans mon
layout ?
• .... Je n’ai pas définit la taille de mon
Drawable
• setBounds(), getIntrinsic[Width/Height]()
9
20. « How-to » basique
La solution !
private Drawable mDrawable;
public DrawableView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mDrawable = context.getResources().getDrawable(R.drawable.my_drawable);
mDrawable.setBounds(0, 0, mDrawable.getIntrinsicWidth(),
mDrawable.getIntrinsicHeight());
}
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
mDrawable.draw(canvas);
}
10
23. Quelques fonctionnalités
Drawable.Callback
• Un Drawable doit pouvoir « s’invalider
»
• Utilité de l’interface Drawable.Callback
• View implémente Drawable.Callback
• Méthode d’aide verifyDrawable()
13
24. Quelques fonctionnalités
Drawable.Callback
public class DrawableView extends View {
private Drawable mDrawable;
public DrawableView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mDrawable = context.getResources().getDrawable(R.drawable.my_drawable);
mDrawable.setBounds(0, 0, mDrawable.getIntrinsicWidth(),
mDrawable.getIntrinsicHeight());
}
@Override
protected boolean verifyDrawable(Drawable who) {
return who == mDrawable || super.verifyDrawable(who);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mDrawable.draw(canvas);
}
}
14
25. Principe d’état constant
Problématique
private static final int OPAQUE = 255;
private static final int TRANSLUCENT = 70;
Book book = ...;
TextView listItem = ...;
listItem.setText(book.getTitle());
Drawable star = getContext().getResources().getDrawable(R.drawable.star);
if (book.isFavorite()) {
star.setAlpha(OPAQUE);
} else {
star.setAlpha(TRANSLUCENT);
}
Extrait de http://www.curious-creature.org/2009/05/02/drawable-mutations/
15
26. Principe d’état constant
Explication du phéomène
• Android « factorise » les états des
Drawables
• Minimise l’empreinte mémoire
16
31. Principe d’état constant
Résolution du « problème »
• Pas de fonctionnalité « copy-on-write »
• Utilisation de la méthode mutate() :
• Copie de l’état constant
• Mise du flag mMutated à true
• Appel multiple à mutated() sans effet
18
35. Principe d’état constant
Résolution du « problème »
private static final int OPAQUE = 255;
private static final int TRANSLUCENT = 70;
Book book = ...;
TextView listItem = ...;
listItem.setText(book.getTitle());
Drawable star = getContext().getResources().getDrawable(R.drawable.star);
if (book.isFavorite()) {
star.mutate().setAlpha(OPAQUE);
} else {
star.mutate().setAlpha(TRANSLUCENT);
}
Extrait de http://www.curious-creature.org/2009/05/02/drawable-mutations/
20
39. Instancier un drawable
Deux possibilités : Java ...
float density = getContext().getResources().getDisplayMetrics().density;
// gradient from #4e525c to #31343c
int[] colors = new int[] {Color.rgb(78, 82, 92), Color.rgb(49, 52, 60)};
GradientDrawable gradient = new GradientDrawable(Orientation.BOTTOM_TOP,
colors);
gradient.setShape(GradientDrawable.OVAL);
gradient.setStroke((int) (3 * density), Color.WHITE, 4 * density, 5 *
density);
23
40. Instancier un drawable
... et XML
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<gradient
android:startColor="#4e525c"
android:endColor="#31343c"
android:angle="90" />
<stroke
android:width="3dip"
android:color="#fff"
android:dashWidth="4dip"
android:dashGap="5dip" />
</shape>
24
41. Drawable Listing
em o
D
Code disponible sur
http://www.github.com/cyrilmottier/DrawablePresentation
25
42. BitmapDrawable
• Très largement utilisé
• Pourtant méconnu / mal connu
• Souvent utilisé tel quel
• context.getResources().getDrawable(R.drawable.image)
(où image est un fichier de type png ou jpg)
• Contrôles plus poussés disponibles
• tileMode, gravity, etc.
26
55. A quoi ça sert tout ça?
Flatten Hierarchy
em o
D
Code disponible sur
http://www.github.com/cyrilmottier/DrawablePresentation
37
56. Créer son Drawable
• Étendre de Drawable (ou une classe
fille)
• Définir les méthodes abstraites
• setAlpha, setColorFilter, draw, etc.
• Redéfinir si nécessaire
38
57. RemoteDrawable
em o
D
Code disponible sur
http://www.github.com/cyrilmottier/DrawablePresentation
39
58. Références
• En savoir plus :
• http://android.cyrilmottier.com
• Code source :
• http://android.git.kernel.org/
• http://github.com/cyrilmottier
40
L&#x2019;objet de cette pr&#xE9;sentation : les Drawables !
Pourquoi : tout simplement parce que je trouve que c&#x2019;est une ressource inexploit&#xE9;e du framework Android !
De plus peu de programmeurs ont une v&#xE9;ritable connaissance des Drawables.
J&#x2019;aimerai commencer par une petite note g&#xE9;n&#xE9;rale : Ne sachant pas trop comment organiser tout &#xE7;a j&#x2019;ai pr&#xE9;f&#xE9;r&#xE9; rassembler les diff&#xE9;rentes petites remarques ici.
Tout d&#x2019;abord je me pr&#xE9;sente :
- Je m&#x2019;appelle Cyril Mottier, je suis ing&#xE9;nieur d&#xE9;veloppement sur plateforme mobile (Android et iPhone : c&#x2019;est cool de connaitre les deux car je peux comparer les d&#xE9;fauts/avantages de chacunes des plateformes).
- Je suis l&#x2019;auteur d&#x2019;un blog de d&#xE9;veloppement francophone sur Android (pourquoi francophone? tout simplement parce qu&#x2019;il y a rien de francophone ... pourtant j&#x2019;aurais pr&#xE9;f&#xE9;r&#xE9; faire de l&#x2019;anglais)
- Sur le Market, j&#x2019;ai fait MetroMap Paris (que vous avez peut etre utilis&#xE9; en venant ici &#xE0; Paris :D).
Pour information :
- J&#x2019;aimerai d&#x2019;abord remercier toute l&#x2019;organisation de m&#x2019;avoir invit&#xE9;
- La pr&#xE9;sentation a &#xE9;t&#xE9; fait un peu dans la pr&#xE9;cipitation donc il est possible que je m&#x2019;aborde pas forc&#xE9;ment bien les probl&#xE9;matiques ou tout simplement que je parle mal/faussement ... Veuillez m&#x2019;en excuser :).
- N&#x2019;h&#xE9;sitez pas &#xE0; poser des questions durant la pr&#xE9;sentation si un point vous intrigue.
Je vous pose la question : &#xAB; C&#x2019;est quoi un Drawable ? &#xBB;
- D&#x2019;un point de vue global, un Drawable d&#xE9;signe un objet qui peut &#xEA;tre dessin&#xE9;/affich&#xE9; (traduction b&#xEA;te et m&#xE9;chante du nom anglais). Bizarrement, un texte pourrait &#xEA;tre consid&#xE9;r&#xE9; comme un Drawable mais &#xE7;a n&#x2019;est pas le cas car il n&#x2019;existe pas de TextDrawable ... &#xE0; vous de le coder? :)
- Dans le framework Android c&#x2019;est un composant &#xE9;l&#xE9;mentaire puisque c&#x2019;est le moyen privil&#xE9;gi&#xE9; pour afficher un composant graphique (image, gradient, etc.)
Je vous pose la question : &#xAB; C&#x2019;est quoi un Drawable ? &#xBB;
- D&#x2019;un point de vue global, un Drawable d&#xE9;signe un objet qui peut &#xEA;tre dessin&#xE9;/affich&#xE9; (traduction b&#xEA;te et m&#xE9;chante du nom anglais). Bizarrement, un texte pourrait &#xEA;tre consid&#xE9;r&#xE9; comme un Drawable mais &#xE7;a n&#x2019;est pas le cas car il n&#x2019;existe pas de TextDrawable ... &#xE0; vous de le coder? :)
- Dans le framework Android c&#x2019;est un composant &#xE9;l&#xE9;mentaire puisque c&#x2019;est le moyen privil&#xE9;gi&#xE9; pour afficher un composant graphique (image, gradient, etc.)
Je vous pose la question : &#xAB; C&#x2019;est quoi un Drawable ? &#xBB;
- D&#x2019;un point de vue global, un Drawable d&#xE9;signe un objet qui peut &#xEA;tre dessin&#xE9;/affich&#xE9; (traduction b&#xEA;te et m&#xE9;chante du nom anglais). Bizarrement, un texte pourrait &#xEA;tre consid&#xE9;r&#xE9; comme un Drawable mais &#xE7;a n&#x2019;est pas le cas car il n&#x2019;existe pas de TextDrawable ... &#xE0; vous de le coder? :)
- Dans le framework Android c&#x2019;est un composant &#xE9;l&#xE9;mentaire puisque c&#x2019;est le moyen privil&#xE9;gi&#xE9; pour afficher un composant graphique (image, gradient, etc.)
- Permet de g&#xE9;rer plus facile les diff&#xE9;rentes r&#xE9;solutions/densit&#xE9;s (c&#x2019;est cet objet qui g&#xE8;re partiellement - en coordoniation avec les layouts/vues - le redimensionnement)
- Les Drawables facilitent l&#x2019;utilisation de ressources graphiques tout en augmentant les possibilit&#xE9;s :
- Un contr&#xF4;le pr&#xE9;cis de l&#x2019;affichage par des propri&#xE9;t&#xE9;s avanc&#xE9;es (setAlpha, setColorFilter, propri&#xE9;t&#xE9;s relatives &#xE0; chaque Drawable comme la gravity ou tileMode sur un BitmapDrawable)
- Possibilit&#xE9;s vari&#xE9;es gr&#xE2;ce &#xE0; l&#x2019;architecture en pattern composite des Drawables (cf slide suivant)
- Enfin les Drawables sont tellement bien int&#xE9;gr&#xE9; au syst&#xE8;me qu&#x2019;il vous permette de modifier l&#x2019;apparence globale des widgets Android sans m&#xEA;me les &#xE9;tendre ou les r&#xE9;&#xE9;crire (View.setBackground() par exemple).
- Arbre de la hi&#xE9;rarchie des Drawables : il y a des classes abstraites (Drawable, DrawableContainer, etc.) et le pattern Composite => un Drawable contient un Drawable
- Une hi&#xE9;rarchie assez cons&#xE9;quente (environ 15 Drawables diff&#xE9;rents dont on peut trouver un exemple dans les sources relatives &#xE0; cette pr&#xE9;sentation)
- Une hi&#xE9;rarchie &#xE0; l&#x2019;instar de View, ViewGroup, etc. (des Drawable dans d&#x2019;autres Drawables)
- Arbre de la hi&#xE9;rarchie des Drawables : il y a des classes abstraites (Drawable, DrawableContainer, etc.) et le pattern Composite => un Drawable contient un Drawable
- Une hi&#xE9;rarchie assez cons&#xE9;quente (environ 15 Drawables diff&#xE9;rents dont on peut trouver un exemple dans les sources relatives &#xE0; cette pr&#xE9;sentation)
- Une hi&#xE9;rarchie &#xE0; l&#x2019;instar de View, ViewGroup, etc. (des Drawable dans d&#x2019;autres Drawables)
- Arbre de la hi&#xE9;rarchie des Drawables : il y a des classes abstraites (Drawable, DrawableContainer, etc.) et le pattern Composite => un Drawable contient un Drawable
- Une hi&#xE9;rarchie assez cons&#xE9;quente (environ 15 Drawables diff&#xE9;rents dont on peut trouver un exemple dans les sources relatives &#xE0; cette pr&#xE9;sentation)
- Une hi&#xE9;rarchie &#xE0; l&#x2019;instar de View, ViewGroup, etc. (des Drawable dans d&#x2019;autres Drawables)
Et s&#x2019;il vous plait : ne me faites pas de new dans le onDraw ... je vois &#xE7;a trop souvent et &#xE7;a m&#x2019;horrifie :) ... J&#x2019;aime d&#xE9;signer les d&#xE9;veloppeurs comme les fautifs des plaintes du public fasse &#xE0; Android : Si vous faites de la merde, c&#x2019;est tout Android qui prend. VOUS &#xEA;tes les promoteurs de cette superbe plateforme !
- Mon canvas n&#x2019;est pas dans un &#xE9;tat acceptable? (canvas.translate(2000, 2000) ...) => NON
- J&#x2019;ai zapp&#xE9; d&#x2019;inclure ma vue dans le layout qui s&#x2019;affiche => &#xC7;a m&#x2019;arrive de temps &#xE0; autre ... trop souvent m&#xEA;me :D ... mais cette fois j&#x2019;ai bien fait attention et ce n&#x2019;est pas &#xE7;a !
- La solution ??? J&#x2019;ai oubli&#xE9; de d&#xE9;finir la taille de mon Drawable ! (setBounds).
- Mon canvas n&#x2019;est pas dans un &#xE9;tat acceptable? (canvas.translate(2000, 2000) ...) => NON
- J&#x2019;ai zapp&#xE9; d&#x2019;inclure ma vue dans le layout qui s&#x2019;affiche => &#xC7;a m&#x2019;arrive de temps &#xE0; autre ... trop souvent m&#xEA;me :D ... mais cette fois j&#x2019;ai bien fait attention et ce n&#x2019;est pas &#xE7;a !
- La solution ??? J&#x2019;ai oubli&#xE9; de d&#xE9;finir la taille de mon Drawable ! (setBounds).
- Mon canvas n&#x2019;est pas dans un &#xE9;tat acceptable? (canvas.translate(2000, 2000) ...) => NON
- J&#x2019;ai zapp&#xE9; d&#x2019;inclure ma vue dans le layout qui s&#x2019;affiche => &#xC7;a m&#x2019;arrive de temps &#xE0; autre ... trop souvent m&#xEA;me :D ... mais cette fois j&#x2019;ai bien fait attention et ce n&#x2019;est pas &#xE7;a !
- La solution ??? J&#x2019;ai oubli&#xE9; de d&#xE9;finir la taille de mon Drawable ! (setBounds).
- Mon canvas n&#x2019;est pas dans un &#xE9;tat acceptable? (canvas.translate(2000, 2000) ...) => NON
- J&#x2019;ai zapp&#xE9; d&#x2019;inclure ma vue dans le layout qui s&#x2019;affiche => &#xC7;a m&#x2019;arrive de temps &#xE0; autre ... trop souvent m&#xEA;me :D ... mais cette fois j&#x2019;ai bien fait attention et ce n&#x2019;est pas &#xE7;a !
- La solution ??? J&#x2019;ai oubli&#xE9; de d&#xE9;finir la taille de mon Drawable ! (setBounds).
Commen&#xE7;ons donc par d&#xE9;finir quelques fonctionnalit&#xE9;s inh&#xE9;rentes aux Drawables :
- Un Drawable, comme nous venons de le voir, a un emplacement et une taille d&#xE9;finie par setBounds(). Il est &#xE9;galement possible de d&#xE9;terminer la taille &#xAB;pr&#xE9;f&#xE9;r&#xE9;e&#xBB; du Drawable ainsi que &#xE7;a taille minimale (Dans le cas d&#x2019;un Bitmap/NinePatchDrawable c&#x2019;est &#xE9;quivalent)
- Un Drawable peut &#xE9;galement avoir un &#xE9;tat courant et un niveau courant : cette fonctionnalit&#xE9; n&#x2019;est pas utilis&#xE9;e dans l&#x2019;int&#xE9;gralit&#xE9; des Drawables mais nous y reviendront dans la suite de cette pr&#xE9;sentation.
- Enfin, puisque les Drawables sont des entit&#xE9;s graphiques, il est possible de modifier leur aspect lors du rendu comme le niveau de transparence, tramage ou non, etc.
- Pour s&#x2019;animer, bouger, tourner, etc .. en clair changer, un Drawable doit pouvoir se redessiner. Or cette fonction est propre &#xE0; la classe View (m&#xE9;thode invalidate() et postInvalidate()). C&#x2019;est donc l&#x2019;utilit&#xE9; de la m&#xE9;thode invalidateDrawable() de Drawable.Callback.
- Un Drawable dispose d&#x2019;une r&#xE9;f&#xE9;rence sur une classe qui impl&#xE9;mente Drawable.Callback. Il s&#x2019;av&#xE8;re que View impl&#xE9;mente cette derni&#xE8;re et fournit une m&#xE9;thode d&#x2019;aide : verifyDrawable(Drawable). Lorsqu&#x2019;un Drawable &#xAB;veut&#xBB; s&#x2019;invalider, il appelle invalidateDrawable(). La classe View impl&#xE9;mente cette m&#xE9;thode et effectue un invalidate() ssi verifyDrawable(d) renvoie vrai.
Le code c&#x2019;est cool mais Android apporte une fonctionnalit&#xE9; tr&#xE8;s int&#xE9;ressante qui consiste &#xE0; d&#xE9;finir par des fichiers XML toutes entit&#xE9;s relative &#xE0; l&#x2019;UI. Les Drawables ne d&#xE9;rogent pas &#xE0; la r&#xE8;gles!
Le code c&#x2019;est cool mais Android apporte une fonctionnalit&#xE9; tr&#xE8;s int&#xE9;ressante qui consiste &#xE0; d&#xE9;finir par des fichiers XML toutes entit&#xE9;s relative &#xE0; l&#x2019;UI. Les Drawables ne d&#xE9;rogent pas &#xE0; la r&#xE8;gles!
C&#x2019;est inutile de faire &#xE7;a parce que &#xE7;a revient &#xE0; faire un getDrawable(R.drawable.pattern) (mode par d&#xE9;faut).
C&#x2019;est inutile de faire &#xE7;a parce que &#xE7;a revient &#xE0; faire un getDrawable(R.drawable.pattern) (mode par d&#xE9;faut).
En mode &#xAB; clamp &#xBB;, les ar&#xEA;tes droites et inf&#xE9;rieures sont r&#xE9;p&#xE9;t&#xE9;es pour remplir l&#x2019;int&#xE9;gralit&#xE9; des &#xAB;bounds&#xBB;
Via XML il sert &#xE0; rien .... :(
Via XML il sert &#xE0; rien .... :(
Via XML il sert &#xE0; rien .... :(
Via XML il sert &#xE0; rien .... :(
Via XML il sert &#xE0; rien .... :(
Via XML il sert &#xE0; rien .... :(
C&#x2019;est l&#x2019;impl&#xE9;mentation la plus aboutie que je connaissent des image &#xE9;tirables :
- sous iPhone : sym&#xE9;trique et sur les ar&#xEA;tes ..
- en CSS3 : sur les ar&#xEA;tes
En Android ; c&#x2019;est des N-patchs ! (zones &#xE9;tirables multiples) et proportionnellement &#xE9;tir&#xE9;es. Surtout : l&#x2019;information des zones &#xE9;tirables et du padding et incluses DANS l&#x2019;image ! C&#x2019;est parfait alors que sous iPhone, cette information est dans le code ...
Montrer que le splash screen de MetroMap Paris peut &#xEA;tre r&#xE9;alis&#xE9; &#xE0; l&#x2019;aide d&#x2019;un unique FrameLayout !!!! (pouss&#xE9; &#xE0; l&#x2019;extr&#xEA;me)
Bien pr&#xE9;ciser que j&#x2019;ai fait celui l&#xE0; dans la pr&#xE9;cipitation et donc que le syst&#xE8;me est loin d&#x2019;&#xEA;tre parfait ... Mais l&#x2019;id&#xE9;e est l&#xE0; :)
- En savoir plus : sur le m&#xEA;me sujet, vous pourrez d&#xE9;couvrir un article expliquant comment cr&#xE9;er ses propres boutons (StateListDrawable) et un autre sur les nine-patch (NinePatchDrawable). Beaucoup d&#x2019;articles divers pour rendre vos UI rapides et belles : pour r&#xE9;sumer faire de vos UI un succ&#xE8;s !
- Code source :
- Avoir acc&#xE8;s au code source d&#x2019;Android est une merveilleuse opportunit&#xE9; de bien s&#x2019;approprier la plateforme. N&#x2019;h&#xE9;sitez pas &#xE0; faire un tour dedans ... je vais m&#xEA;me faire suivre la bonne parole des Googlers : Aidez les en soumettant vos patchs !
- GitHub : le code source de l&#x2019;application de d&#xE9;monstration est disponible sur ce site.
Voil&#xE0; ! C&#x2019;est fini ... j&#x2019;esp&#xE8;re avoir r&#xE9;pondu &#xE0; vos attentes et surtout vous avoir montrer de nouvelles facettes inexploit&#xE9;es du syst&#xE8;me Android. H&#x2019;h&#xE9;sitez pas &#xE0; poser vos questions !
Bien s&#xFB;r je serais disponible par la suite si vous le souhaitez pour r&#xE9;pondre &#xE0; des questions dans un mode plus &#xAB; priv&#xE9; &#xBB;.