J'exploite les deux constructeurs destinés à l'inflation pour pouvoir récupérer les attributs que j'ai pu passer en attributs. En effet, il m'est possible de définir mes propres attributs pour ma vue. Pour cela, il me faut créer des ressources de type attr dans un tableau d'attributs. Ce tableau est un nœud de type declare-styleable. J'attribue un nom à chaque élément qui leur servira d'identifiant. Enfin, je peux dire pour chaque attr quel type d'informations il contiendra.
Code : XML <resources>
<declare-styleable name="ChessBoardView">
<!-- L'attribut d'identifiant "colorOne" est de type "color" -->
<attr name="colorTwo" format="color"/> </declare-styleable>
</resources>
Pour utiliser ces attributs dans le layout, il faut tout d'abord déclarer utiliser un namespace, comme on le fait pour pouvoir utiliser les attributs qui appartiennent à Android :
xmlns:android="http://schemas.android.com/apk/res/android" .
Cette déclaration nous permet d'utiliser les attributs qui commencent par android: dans notre layout, elle nous permettra donc d'utiliser nos propres attributs de la même manière.
Pour cela, on va se contenter d'agir d'une manière similaire en remplaçant xmlns:android par le nom voulu de notre
namespace et http://schemas.android.com/apk/res/android par notre package actuel. Dans mon cas, j'obtiens : Code : Console
xmlns:sdzName="http://schemas.android.com/apk/res/sdz.chapitreDeux.chessBoard"
Ce qui me donne ce XML : Code : XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:sdzName="http://schemas.android.com/apk/res/sdz.chapitreDeux.chessBoard" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <sdz.chapitreDeux.chessBoard.ChessBoardView android:layout_width="fill_parent" android:layout_height="fill_parent" sdzName:colorOne="#FF0000" sdzName:colorTwo="#00FF00" /> </LinearLayout>
Il me suffit maintenant de récupérer les attributs comme nous l'avions fait précédemment : Code : Java
// attrs est le paramètre qui contient les attributs de notre objet en XML
public ChessBoardView(Context context, AttributeSet attrs, int
defStyle) {
super(context, attrs, defStyle); init(attrs);
}
// idem
public ChessBoardView(Context context, AttributeSet attrs) { super(context, attrs);
init(attrs); }
R.styleable.ChessBoardView);
// Il s'agit d'un TypedArray qu'on sait déjà utiliser, je récupère la valeur de la couleur 1 ou "-1" si on la trouve pas int tmpOne = attr.getColor(R.styleable.ChessBoardView_colorOne, -1);
// Je récupère la valeur de la couleur 2 ou "-1" si on la trouve pas
int tmpTwo = attr.getColor(R.styleable.ChessBoardView_colorTwo, -1);
init(tmpOne, tmpTwo); }
onMeasure
La taille par défaut de 100 pixels est ridicule et ne conviendra jamais à un échiquier. Je vais faire en sorte que si l'application me l'autorise, je puisse exploiter le carré le plus grand possible, et je vais faire en sorte qu'au pire, notre vue prenne au moins la moitié de l'écran.
Pour cela, j'ai écrit une méthode qui calcule la dimension la plus grande entre la taille que me demande de prendre le layout et la taille qui correspond à la moitié de l'écran. Puis je compare en largeur et en hauteur quelle est la plus petite taille accordée, et mon échiquier s'accorde à cette taille.
Il existe plusieurs méthodes pour calculer la taille de l'écran. De mon côté, j'ai fait en sorte de l'intercepter depuis les ressources avec la méthode DisplayMetrics getDisplayMetrics (). Je récupère ensuite l'attribut heightPixels pour avoir la hauteur de l'écran et widthPixels pour sa largeur.
Code : Java /**
* Calcule la bonne mesure sur un axe uniquement * @param spec - Mesure sur un axe
* @param screenDim - Dimension de l'écran sur cet axe * @return la bonne taille sur cet axe
*/
private int singleMeasure(int spec, int screenDim) { int mode = MeasureSpec.getMode(spec);
int size = MeasureSpec.getSize(spec);
// Si la layout n'a pas précisé de dimensions, la vue prendra la moitié de l'écran
if(mode == MeasureSpec.UNSPECIFIED) return screenDim/2;
else
// Sinon, elle prendra la taille demandée par le layout return size;
}
@Override
protected void onMeasure (int widthMeasureSpec, int
heightMeasureSpec) {
// On récupère les dimensions de l'écran DisplayMetrics metrics =
getContext().getResources().getDisplayMetrics(); // Sa largeur...
int screenWidth = metrics.widthPixels; // ... et sa hauteur
int screenHeight = metrics.heightPixels;
int retourWidth = singleMeasure(widthMeasureSpec, screenWidth); int retourHeight = singleMeasure(heightMeasureSpec,
screenHeight);
// Comme on veut un carré, on aura qu'une taille pour les deux axes, la plus petite possible
int retour = Math.min(retourWidth, retourHeight);
setMeasuredDimension(retour, retour); }
Toujours avoir dans son implémentation de onMeasure un appel à la méthode void setMeasuredDimension
(int measuredWidth, int measuredHeight), sinon votre vue vous enverra une exception.
onDraw
Il ne reste plus qu'à dessiner notre échiquier ! Ce n'est pas grave si vous ne comprenez pas l'algorithme, du moment que vous avez compris toutes les étapes qui me permettent d'afficher cet échiquier tant voulu.
Code : Java
@Override
protected void onDraw(Canvas canvas) { // Largeur de la vue
int width = getWidth(); // Hauteur de la vue int height = getHeight();
int step = 0, min = 0;
// La taille minimale entre la largeur et la hauteur min = Math.min(width, height);
// Comme on ne veut que 8 cases par lignes et 8 lignes, on divise la taille par 8
step = min / 8;
// Détermine quand on doit changer la couleur entre deux cases boolean switchColor = true;
for(int i = 0 ; i < min ; i += step) { for(int j = 0 ; j < min ; j += step) { if(switchColor)
canvas.drawRect(i, j, i + step, j + step, mPaintTwo); else
canvas.drawRect(i, j, i + step, j + step, mPaintOne); // On change de couleur entre chaque ligne... switchColor = !switchColor;
}
// ...et entre chaque case switchColor = !switchColor; }
}
Partie 3 : Annexes
L'architecture d'Android
Après quelques réflexions et quelques recherches, je me suis dit que c'était peut-être une bonne idée de présenter aux plus curieux l'architecture d'Android. Vous pouvez considérer ce chapitre comme facultatif s'il vous ennuie ou vous semble trop compliqué, vous serez tout de même capable de développer correctement sous Android mais un peu de culture technique ne peut pas vous faire de mal .
Concrètement, l'architecture d'Android, c'est ça :
Schéma qui provient de la page suivante, provenant du site d'Android destiné aux développeurs.
En soi, ce schéma est incompréhensible et franchement pas glamour, mais il résume de manière concrète ce que je vais vous raconter. Ce que vous observez est une pile des composants qui constituent le système d'exploitation. Le sens de lecture se fait de bas en haut, puisque le composant de plus bas niveau est le noyau Linux et celui de plus haut niveau sont les applications.