You are on page 1of 17

Cration d'une boussole

par Davy Leggieri (Page de l'auteur)


Date de publication : 13 fvrier 2010 Dernire mise jour : 3 avril 2010

Ce tutoriel va vous prsenter, de faon globale, comment crer une vue et l'animer.

Cration d'une boussole par Davy Leggieri (Page de l'auteur)

I - Introduction..............................................................................................................................................................3 I-A - Le rsultat...................................................................................................................................................... 3 I-B - Version du SDK utilis................................................................................................................................... 3 II - Cration de la vue................................................................................................................................................. 3 II-A - Spcification.................................................................................................................................................. 3 II-B - Ralisation.....................................................................................................................................................4 II-B-1 - La mthode onMeasure....................................................................................................................... 5 II-B-2 - La mthode onDraw............................................................................................................................. 6 II-B-2-a - Canvas save et restore............................................................................................................... 8 II-B-2-a-i - Intrt....................................................................................................................................8 II-B-2-a-ii - Fonctionnement................................................................................................................... 8 III - Exemple d'utilisation de la vue boussole..............................................................................................................8 IV - Mettre jour la vue grce la boussole numrique......................................................................................... 10 IV-A - Listener excut lorsque la boussole numrique possde une nouvelle orientation.................................10 IV-B - Lier le changement d'orientation de la boussole numrique notre listener............................................ 11 V - Animation de la boussole.................................................................................................................................... 12 V-A - La technique utilise...................................................................................................................................12 V-B - Les modifications du code..........................................................................................................................12 V-C - Amliorer l'animation.................................................................................................................................. 14 V-D - Forcer le sens de rotation de l'aiguille....................................................................................................... 15 V-E - Critique........................................................................................................................................................16 VI - Conclusion.......................................................................................................................................................... 17 VII - Remerciements.................................................................................................................................................. 17 VIII - Liens..................................................................................................................................................................17

-2Copyright 2010 - Davy Leggieri. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://davy-leggieri.developpez.com/tutoriels/android/creation-boussole/

Cration d'une boussole par Davy Leggieri (Page de l'auteur)

I - Introduction
Ce tutoriel a pour objectif de vous permettre de crer une boussole. Celle-ci ragira en fonction de l'orientation de votre tlphone, pourvu que votre mobile soit muni d'une boussole numrique. Outre le rsultat final, l'intrt majeur de ce tutoriel est d'aborder la cration d'une vue et son animation. Nous allons ainsi aborder les principes de bases ncessaires la cration et l'animation d'une vue personnalise, mais galement les manipulations lmentaires d'un canevas sous Android.

I-A - Le rsultat

La boussole que nous allons crer la fin de ce tutoriel, vous obtiendrez la boussole ci-dessus. Celle-ci ne brille pas forcment de par son design, mais a le mrite d'tre anime et de laisser libre cours votre imagination pour l'agrmenter.

I-B - Version du SDK utilis


Ce tutoriel a t compil avec la version 1.5 du SDK, et le code utilis reste inchang jusqu' (au moins) la version 2.1 du SDK.

II - Cration de la vue
Dans cette partie, nous allons prsenter uniquement la cration de la vue de la boussole. Ainsi, on abordera l'hritage des classes de bases du SDK, ainsi que les mthodes lmentaires redfinir.

II-A - Spcification
Notre classe CompassView devra tre capable d'afficher une boussole pointant son aiguille vers le nord. Pour ce faire, notre vue aura deux mthodes : la premire pour indiquer l'orientation du nord, la seconde pour rcuprer cette valeur. La classe possdera donc un attribut priv northOrientation qui permettra de sauvegarder en interne l'orientation du nord en degrs. Cette orientation sera comprise entre 0 et 360, et suivra la convention suivante :

-3Copyright 2010 - Davy Leggieri. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://davy-leggieri.developpez.com/tutoriels/android/creation-boussole/

Cration d'une boussole par Davy Leggieri (Page de l'auteur)

Convention adopte pour l'orientation

II-B - Ralisation
Tous les lments graphiques de bases sous Android (TextView, CheckBox, etc.) hritent de la classe View. Cette classe View est la brique de base permettant de construire l'interface homme-machine d'une application. C'est elle qui dessine sur l'cran et qui intercepte les actions de l'utilisateur (toucher une zone de l'cran par exemple). Pour crer la vue de notre boussole, nous allons crer une classe CompassView qui va hriter de la classe View. D'aprs les spcifications de notre vue prsentes prcdemment, nous pouvons aboutir la classe incomplte suivante : CompassView.java
public class CompassView extends View { //~--- fields ------------------------------------------------------------//Rotation vers la droite en degree pour pointer le Nord private float northOrientation=0; //~--- constructors ------------------------------------------------------public CompassView(Context context) { super(context); } // Constructeur utilis pour instancier la vue depuis sa // dclaration dans un fichier XML public CompassView(Context context, AttributeSet attrs) { super(context, attrs); } // idem au prcdant public CompassView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } //~--- get methods -------------------------------------------------------// permet de rcuprer l'orientation de la boussole public float getNorthOrientation() { return northOrientation; } //~--- set methods -------------------------------------------------------// permet de changer l'orientation de la boussole public void setNorthOrientation(float rotation) { -4Copyright 2010 - Davy Leggieri. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://davy-leggieri.developpez.com/tutoriels/android/creation-boussole/

Cration d'une boussole par Davy Leggieri (Page de l'auteur)

CompassView.java

//on met jour l'orientation uniquement si elle a chang if (rotation != this.northOrientation) { this.northOrientation = rotation; //on demande notre vue de se redessiner this.invalidate(); } }

Notre classe contient prsent les donnes et les mthodes lmentaires qui seront utilises pour la manipuler. Nous allons maintenant nous concentrer sur le coeur de mtier de cette classe, c'est dire l'affichage de la boussole en elle-mme. Une grande partie du code va tre concentre dans deux mthodes hrites de la classe View : onMeasure; onDraw.

La premire mthode, onMeasure, est appele lors de l'instanciation de notre vue par son parent. Cette mthode permet notre vue de dclarer la taille sur l'cran qui lui est ncessaire pour se dessiner. La seconde mthode, onDraw, est appele lorsque la vue doit dessiner son contenu, c'est dans celle-ci que nous userons du pinceau pour dessiner notre boussole. Voici un tableau rsumant ce que nous venons de dire : Catgorie Layout Drawing Mthodes onMeasure(int, int) onDraw(Canvas) Description Appele pour dterminer la taille de la vue (et de ses enfants) Appele quand la vue doit dessiner son contenu

II-B-1 - La mthode onMeasure


La mthode onMeasure permet notre vue de dclarer, la vue qui est hirarchiquement suprieure, la taille qui lui est ncessaire pour se dessiner l'cran. Il faut savoir que si cette mthode n'est pas redfinie, notre vue fera par dfaut 100x100 pixels et que par consquent, quand bien mme vous dessineriez de grandes choses, vous ne verrez rien au-del de ce carr de 100x100 pixels que forme votre vue. Dans le cas de la boussole, nous allons laisser notre vue tre un carr aussi grand que possible, c'est dire, aussi grand que le propose la vue parente de notre boussole. Comment est-ce possible ? Il nous suffit de regarder du ct des paramtres d'appel de onMeasure. Les deux paramtres widthMeasureSpec et heightMeasureSpec contiennent l'ventuelle taille que le parent se propose d'offrir notre vue. Vous avez bien lu "ventuelle ", car c'est ce niveau que les choses se complexifient. Il nous faudra donc tester ces paramtres, et forcer une taille par dfaut si le parent ne nous permet pas de recueillir les informations concernant la taille disponible. CompassView.java
//~--- methods -----------------------------------------------------------// Permet de dfinir la taille de notre vue // /!\ par dfaut un cadre de 100x100 si non redfini @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int measuredWidth = measure(widthMeasureSpec); int measuredHeight = measure(heightMeasureSpec); // Notre vue sera un carr, on garde donc le minimum int d = Math.min(measuredWidth, measuredHeight); setMeasuredDimension(d, d); -5Copyright 2010 - Davy Leggieri. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://davy-leggieri.developpez.com/tutoriels/android/creation-boussole/

Cration d'une boussole par Davy Leggieri (Page de l'auteur)

CompassView.java
} // Dterminer la taille de notre vue private int measure(int measureSpec) { int result = 0; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); if (specMode == MeasureSpec.UNSPECIFIED) { // Le parent ne nous a pas donn d'indications, // on fixe donc une taille result = 150; } else { // On va prendre la taille de la vue parente result = specSize; } } return result;

II-B-2 - La mthode onDraw


Aprs avoir dclar la taille de notre vue (via la mthode onMeasure), nous allons dessiner l'intrieur de celle-ci en utilisant la mthode onDraw. Cette mthode sera appele "automatiquement" lors du premier dessin de la fentre (ou chaque fois que l'on appellera explicitement la mthode invalidate de notre vue). Avant de procder la phase du dessin, nous devons repenser notre faon de programmer : notre code doit tre optimis autant que possible, car la fluidit de notre animation dpendra de cette portion de code. Notre petit robot vert est muni d'un Garbage Collector assez simple qui, pour faire le mnage, bloque l'excution du programme pendant 100 ms (plus spcifiquement l'excution du thread responsable de l'interface graphique, l'UI thread). La rsultante du dclenchement du Garbage Collector au moment de la procdure de dessin est un affichage saccad (trs visible dans les animations). Une tlportation des diffrents lments fera place l'animation proprement dite, ce qui n'est pas trs esthtique. La rgle d'or est donc d'viter autant que possible d'instancier de nouveaux objets dans le code de la mthode onDraw. Pour cela, nous allons commencer par crer une mthode prive initView qui sera appele dans les constructeurs de CompassView.java et qui aura pour but d'instancier tous les objets manipuls dans la mthode onDraw. De cette manire, on instanciera tout ce dont nous aurons besoin pour dessiner, et ainsi notre mthode onDraw n'aura que peu de contenu dynamique ce qui limitera l'excution du GC. CompassView.java
// Constructeur par dfaut de la vue public CompassView(Context context) { super(context); initView();//faire de mme pour les 2 autres constructeurs }

Pour dessiner notre boussole, 4 objets nous sont ncessaires/indispensables. Tout d'abord nous aurons besoin d'un Path trianglePath, qui sera un ensemble de lignes formant un triangle pour dessiner la forme de nos aiguilles. Puis nous aurons besoin de circlePaint, northPaint et southPaint qui seront des " pinceaux " utiliss pour dessiner respectivement l'arrire-plan de la boussole, l'aiguille du nord et celle du sud. Nous dclarerons trois "pinceaux" diffrents car ils nous permettront de dessiner avec des couleurs diffrentes. CompassView.java
//~--- fields private Paint private Paint private Paint ------------------------------------------------------------circlePaint; northPaint; southPaint;

-6Copyright 2010 - Davy Leggieri. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://davy-leggieri.developpez.com/tutoriels/android/creation-boussole/

Cration d'une boussole par Davy Leggieri (Page de l'auteur)

CompassView.java

private Path trianglePath; //~--- methods -----------------------------------------------------------private void initView() { Resources r = this.getResources(); // Paint pour l'arrire plan de la boussole circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG); // Lisser les formes circlePaint.setColor(r.getColor(R.color.compassCircle)); // Dfinir la couleur // Paint pour les 2 aiguilles, Nord et Sud northPaint = new Paint(Paint.ANTI_ALIAS_FLAG); northPaint.setColor(r.getColor(R.color.northPointer)); southPaint = new Paint(Paint.ANTI_ALIAS_FLAG); southPaint.setColor(r.getColor(R.color.southPointer)); // Path pour dessiner les aiguilles trianglePath = new Path();

Remarque : vous pouvez constater que les couleurs ne sont pas codes en dur mais font rfrence un fichier de ressources " R.color.xxx " dcrit ci-dessous.

color.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <color name="northPointer">#FF0000</color> <color name="southPointer">#000000</color> <color name="compassCircle">#CCCCFF</color> </resources>

Voil, le terrain est prsent prt et il ne nous reste plus qu' crire le corps de la fonction pour dessiner. onDraw possde un seul paramtre : le canevas tant l'quivalent d'une toile sur laquelle nous allons dessiner. Toutes les actions de dessins vont donc avoir lieu sur cet objet. Nous allons ainsi utiliser drawCircle pour dessiner un cercle (reprsentant le fond de notre boussole) et des drawPath pour dessiner des formes composes par nous-mmes (reprsentant les aiguilles de notre boussole). CompassView.java
// Appele pour redessiner la vue @Override protected void onDraw(Canvas canvas) { //On dtermine le point au centre de notre vue int centerX = getMeasuredWidth() / 2; int centerY = getMeasuredHeight() / 2; // On dtermine le diamtre du cercle (arrire plan de la boussole) int radius = Math.min(centerX, centerY); // On dessine un cercle avec le " pinceau " circlePaint canvas.drawCircle(centerX, centerY, radius, circlePaint); // On sauvegarde la position initiale du canevas canvas.save();

-7Copyright 2010 - Davy Leggieri. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://davy-leggieri.developpez.com/tutoriels/android/creation-boussole/

Cration d'une boussole par Davy Leggieri (Page de l'auteur)

CompassView.java

// On tourne le canevas pour que le nord pointe vers le haut canvas.rotate(-northOrientation, centerX, centerY); // on crer une forme triangulaire qui part du centre du cercle et // pointe vers le haut trianglePath.reset();//RAZ du path (une seule instance) trianglePath.moveTo(centerX, 10); trianglePath.lineTo(centerX - 10, centerY); trianglePath.lineTo(centerX + 10, centerY); // On dsigne l'aiguille Nord canvas.drawPath(trianglePath, northPaint); // On tourne notre vue de 180 pour dsigner l'auguille Sud canvas.rotate(180, centerX, centerY); canvas.drawPath(trianglePath, southPaint); // On restaure la position initiale (inutile dans notre exemple, mais prvoyant) canvas.restore();

Sous Android, le canevas se manipule comme sous Swing, c'est--dire qu'il s'agit d'une toile qu'on peut dplacer un peu comme une feuille de papier. Vous remarquerez que nous avons dplac le canevas avec "rotate", ce qui nous a permis de le faire tourner autour d'un point. Le centre choisi pour la rotation est tout simplement le centre du cercle. La premire manipulation du canevas est une rotation amenant le nord en haut de notre canevas. Ensuite, nous avons simplement dessin la premire aiguille, puis nous avons fait une rotation de 180 pour dessiner la deuxime aiguille (celle du Sud) oppose la premire.

II-B-2-a - Canvas save et restore


Vous remarquerez que nous avons utilis les deux mthodes save et restore de l'objet canevas qui ne sont pas utiles dans notre exemple du dessin de la boussole, mais que nous allons tout de mme introduire et expliquer.

II-B-2-a-i - Intrt
Ces mthodes permettent de sauvegarder la position initiale du canevas, ainsi toute manipulation de ce dernier (dplacement ou rotation) pourra tre annule.

II-B-2-a-ii - Fonctionnement
Save permet de sauvegarder la position actuelle de votre canevas (ne sauvegarde pas le contenu). Restore permet de restaurer une position de votre canevas.

La sauvegarde et la restauration fonctionnent comme une pile LIFO, c'est--dire que si on sauvegarde une position A puis une position B, le premier appel restore va restaurer la position B et le second la position A. Voil pour la petite histoire sur save et restore, retour donc la vue de notre boussole. Notre vue est prsent finalise, il ne nous reste plus qu' observer le rendu.

III - Exemple d'utilisation de la vue boussole


C'est bien beau tout ce travail, mais on aimerait bien en voir la couleur, n'est-ce pas ? Pour ce faire, il suffit de crer une Activity qui va instancier sa propre interface graphique partir d'un fichier XML. Boussole.java
public class Boussole extends Activity { -8Copyright 2010 - Davy Leggieri. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://davy-leggieri.developpez.com/tutoriels/android/creation-boussole/

Cration d'une boussole par Davy Leggieri (Page de l'auteur)

Boussole.java

@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); }

Dclarons le XML main.xml qui va contenir uniquement notre vue:


<?xml version="1.0" encoding="utf-8"?> <!-Pour utiliser notre vue, il suffit de mettre le nom complet du paquetage de notre classe CompassView--> <com.bydavy.boussole.view.CompassView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/compassView" android:layout_width="fill_parent" android:layout_height="fill_parent"/>

Petite parenthse : vous remarquerez que nous affichons notre vue avec la proprit xmlns :android="http:// schemas.android.com/apk/res/android". Ceci vient du fait que notre Activity ne comportera que la vue de la boussole, cependant, nous pourrions trs bien mettre notre vue dans un LinearLayout ou tout autre Layout. Si nous excutons le programme, nous devrions avoir une jolie boussole qui s'affiche sur l'cran. Pour le moment, l'aiguille du nord pointe stupidement vers le haut. Nous allons donc tenter de modifier l'orientation de l'aiguille du nord. Pour ce faire, nous allons changer le code de notre activity de la manire suivante : Boussole.java
public class Boussole extends Activity { //La vue de notre boussole private CompassView compassView; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //On rcupre notre vue compassView = (CompassView)findViewById(R.id.compassView); //Et on essaie de faire pointer notre aiguille du Nord au point 45 compassView.setNorthOrientation(45); }

-9Copyright 2010 - Davy Leggieri. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://davy-leggieri.developpez.com/tutoriels/android/creation-boussole/

Cration d'une boussole par Davy Leggieri (Page de l'auteur)

Boussole pointant vers 45 On pourra remarquer que l'appel "compassView.setNorthOrientation(45)" a bien modifi l'orientation du nord signal par notre vue. On peut donc conclure que notre classe BoussoleView.java rpond bien aux spcifications que nous avions formules. Nous pouvons maintenant la lier aux donnes de la boussole numrique.

IV - Mettre jour la vue grce la boussole numrique


Une vue fonctionnelle c'est trs bien, mais une vue qui montre des donnes utiles c'est encore mieux. Pour rcuprer les informations de la boussole numrique, nous avons besoin de demander au SensorManager la liste des capteurs de type boussole dont il dispose. Celui-ci va nous retourner une liste de capteurs et nous allons garder uniquement le premier (tout appareil est muni d'une seule boussole numrique, mais le SDK nous impose ce comportement). Ensuite nous allons crer un SensorEventListener qui sera excut chaque fois que notre boussole numrique connatra une nouvelle orientation du tlphone mobile. Pour finir, nous allons lier ce SensorEventListener la boussole numrique. Voici de manire schmatique comment les choses vont se passer :

IV-A - Listener excut lorsque la boussole numrique possde une nouvelle orientation
Nous allons dclarer le listener :

- 10 Copyright 2010 - Davy Leggieri. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://davy-leggieri.developpez.com/tutoriels/android/creation-boussole/

Cration d'une boussole par Davy Leggieri (Page de l'auteur)

Boussole.java
//Notre listener sur le capteur de la boussole numrique private final SensorEventListener sensorListener = new SensorEventListener() @Override public void onSensorChanged(SensorEvent event) { compassView.setNorthOrientation(event.values[SensorManager.DATA_X]); } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } }; {

IV-B - Lier le changement d'orientation de la boussole numrique notre listener


Pour lier le changement d'orientation de la boussole numrique notre listener, nous devons commencer par dclarer le gestionnaire de capteurs et un capteur qui sera la boussole numrique. Boussole.java
//Le gestionnaire des capteurs private SensorManager sensorManager; //Notre capteur de la boussole numrique private Sensor sensor;

Ensuite, nous allons demander au gestionnaire de capteurs les capteurs de type boussole dont il dispose. Boussole.java
/** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); compassView = (CompassView)findViewById(R.id.compassView); //Rcupration du gestionnaire de capteurs sensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE); //Demander au gestionnaire de capteur de nous retourner les capteurs de type boussole List<Sensor> sensors =sensorManager.getSensorList(Sensor.TYPE_ORIENTATION); //s'il y a plusieurs capteurs de ce type on garde uniquement le premier if (sensors.size() > 0) { sensor = sensors.get(0); } }

Pour finir, nous allons demander au gestionnaire de capteurs de lier notre SensorEventListener aux vnements de la boussole numrique lorsque l'application s'affiche. Et inversement, nous allons lui demander de dfaire ce lien lorsque l'on quitte l'application. Boussole.java
@Override protected void onResume(){ super.onResume(); //Lier les vnements de la boussole numrique au listener sensorManager.registerListener(sensorListener, sensor, SensorManager.SENSOR_DELAY_NORMAL); } @Override protected void onStop(){ super.onStop(); //Retirer le lien entre le listener et les vnements de la boussole numrique sensorManager.unregisterListener(sensorListener); } - 11 Copyright 2010 - Davy Leggieri. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://davy-leggieri.developpez.com/tutoriels/android/creation-boussole/

Cration d'une boussole par Davy Leggieri (Page de l'auteur)

Nous disposons maintenant d'une vue qui est mise jour chaque fois qu'une nouvelle orientation est connue par la boussole numrique.

V - Animation de la boussole
Notre application fonctionne parfaitement, mais on observe une certaine tendance la tlportation de notre aiguille, notamment lorsqu'on fait brusquement changer le tlphone de direction. Ceci est d au simple fait qu'on change l'orientation de l'aiguille brutalement. Ainsi, la boussole passe sans transition de l'ancienne valeur la nouvelle. Pour remdier ce problme, je propose qu'on fasse voluer l'aiguille entre l'ancienne et la nouvelle orientation du nord de manire incrmentale et fluide.

V-A - La technique utilise


Lorsqu'une nouvelle orientation sera fournie notre vue grce la mthode SetNorthOrientation, nous sauvegarderons l'orientation courante et l'orientation fournie en paramtre, que nous appellerons respectivement startNorthOrientation et endNorthOrientation. Nous redessinerons ainsi la vue plusieurs fois en faisant varier NorthOrientation entre ces deux valeurs, de telle manire que NorthOrientation parte de startNorthOrientation et se rapproche de plus en plus de endNorthOrientation. Pour redessiner priodiquement notre vue, nous devrons utiliser un Timer. Chaque excution de la tche du timer fera voluer la position courante de l'aiguille et redessinera la vue de la boussole. Ce Timer sera appel toutes les 20ms pendant 1 seconde. Ce qui signifie que l'animation durera 1 seconde et qu'au maximum il y aura 1 000/20 = 50 images par seconde pour donner l'impression d'une animation. Ne pouvant prdire exactement combien d'images par seconde seront affiches au cours de cette seconde d'animation, nous allons dterminer la position de l'aiguille afficher en fonction du pourcentage d'volution de notre animation. Pour produire de telles informations, nous utiliserons le temps coul depuis le dbut de l'animation. Prcdemment, j'ai dit que nous utiliserons un Timer pour dessiner priodiquement la vue. Cependant, le recours un Timer implique par dfinition l'utilisation d'un nouveau thread. Un thread pour de l'animation est-ce bien raisonnable ? Dveloppant pour tlphone portable, nous devons conomiser les ressources notre disposition or la cration d'un thread pour une animation parait dmesure. Nous profiterons donc des fonctionnalits du SDK Android, et nous utiliserons un Handler. Le Handler est capable d'excuter, en diffr, un objet de type Runnable. Ce dernier sera excut dans le UI thread lorsque ce thread n'aura rien faire. Les vues sont dj munis d'un Handler. Les appels aux mthodes post, postDelay et removeCallbacks du Handler seront donc accessible directement depuis notre classe CompassView.

V-B - Les modifications du code


Nous allons ajouter les attributs suivants notre vue: CompassView.java
//Dlais entre chaque image private final int DELAY = 20; //Dure de l'animation private final int DURATION = 1000; private float startNorthOrientation; private float endNorthOrientation; //Heure de dbut de l'animation (ms) private long startTime;

Et nous allons, galement, changer la mthode setNorthOrientation de la manire suivante :


- 12 Copyright 2010 - Davy Leggieri. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://davy-leggieri.developpez.com/tutoriels/android/creation-boussole/

Cration d'une boussole par Davy Leggieri (Page de l'auteur)

CompassView.java
// permet de changer l'orientation de la boussole public void setNorthOrientation(float rotation) { // on met jour l'orientation uniquement si elle a chang if (rotation != this.northOrientation) { //Arrter l'ancienne animation removeCallbacks(animationTask); //Position courante this.startNorthOrientation = this.northOrientation; //Position dsire this.endNorthOrientation = rotation; //Nouvelle animation startTime = SystemClock.uptimeMillis(); postDelayed(animationTask, DELAY); }

La mthode setNorthOrientation va donc sauvegarder la position courante, la nouvelle position dsire de l'aiguille, la date de dbut de l'animation (en ms) et va programmer une premire excution de la tche animationTask du handler. Voici prsent le code de la tche charge de l'animation : CompassView.java
private Runnable animationTask = new Runnable() { public void run() { long curTime = SystemClock.uptimeMillis(); long totalTime = curTime - startTime; if (totalTime > DURATION) { // Fin de l'animation northOrientation = endNorthOrientation; removeCallbacks(animationTask); } else { //Changer la position de l'aiguille //Rappeler cette tche dans DELAY ms pour dessiner la suite postDelayed(this, DELAY); } // Quoi qu'il arrive, on demande notre vue de se redessiner invalidate();

};

Vous remarquerez que dans cette tche nous essayons de dterminer s'il y a plus d'une seconde coule depuis le dbut de l'animation. Si tel est le cas, l'animation devra tre termine, nous mettons alors l'aiguille du nord dans la position finale et nous arrtons toutes les prochaines animations programmes s'il y en a (pas forcment utile). Dans le cas o notre animation se droule depuis moins d'une seconde, nous allons changer la position de l'aiguille, reprogrammer un appel cette tche dans DELAY ms pour continuer l'animation et enfin redessiner la vue. Pour le moment, notre code ne fait pas encore voluer la position de l'aiguille entre chaque appel la tche d'animation. Notre aiguille est seulement dplace sa position finale aprs 1 seconde. Nous allons maintenant mettre en place l'volution de sa position. Admettons que notre aiguille soit 5, et que l'on dsire la ramener 13. Lorsque notre tche d'animation est appele nous allons dterminer quel pourcentage de l'animation nous nous trouvons : CompassView.java
perCent = ((float) totalTime) / DURATION;

- 13 Copyright 2010 - Davy Leggieri. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://davy-leggieri.developpez.com/tutoriels/android/creation-boussole/

Cration d'une boussole par Davy Leggieri (Page de l'auteur)

Et nous allons ainsi modifier la position de l'aiguille pour qu'elle soit x perCent entre sa position initiale de 5 et sa position finale de 13, ce qui nous donne : CompassView.java
northOrientation = (float) (startNorthOrientation + perCent * (endNorthOrientation startNorthOrientation));

Au final, nous arrivons donc au code suivant : CompassView.java


if (totalTime > DURATION) { ? } else { float perCent = ((float) totalTime) / DURATION; //On s'assure qu'on ne dpassera pas 1. perCent = Math.min(perCent, 1); //On determine la nouvelle position de l'aiguille northOrientation = (float) (startNorthOrientation + perCent * (endNorthOrientation startNorthOrientation)); postDelayed(this, DELAY); } // Quoi qu'il arrive, on demande notre vue de se redessiner invalidate();

Le code tant complet, nous pouvons tester l'animation de notre boussole frachement cre. Vous remarquerez que l'aiguille ne se tlporte plus lors du soudain changement d'orientation. Cependant, l'aiguille volue de manire bizarre, puisque qu'elle volue toujours la mme vitesse pour aller de sa position de dpart sa position finale, peut importe qu'elle soit trs loin du nord magntique ou juste ct. Pour le moment, le rsultat est bien loin d'tre raliste.

V-C - Amliorer l'animation


Pour donner plus de crdibilit notre animation nous allons essayer de trouver une fonction mathmatique, non linaire, qui volue entre 0 et 1 (valeur de perCent). Cette fonction devra crotre rapidement au voisinage de 0, puis rduire sa croissance l'approche de 1. Pour cela, il semble intressant d'utiliser la fonction sinus qui a le comportement recherch. Nous devrons juste modifier son amplitude pour s'assurer que pour la valeur 1 (de notre perCent) la fonction nous retourne bien 1, c'est--dire qu' 100% de notre animation nous affichons bien la fin de l'animation. Ainsi, la fonction retenue sera sinus(x * 1.5).

Sinus(x*1.5) Valeurs prises entre 0 et 1 : X Y 0 0 0.2 0.29 0.4 0.56 0.6 0.78 0.8 0.93 1 1

- 14 Copyright 2010 - Davy Leggieri. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://davy-leggieri.developpez.com/tutoriels/android/creation-boussole/

Cration d'une boussole par Davy Leggieri (Page de l'auteur)

Nous avons donc une forte acclration entre 0 et 0,6 ce qui permet de faire voluer rapidement notre aiguille vers la position finale en dbut d'animation, alors qu'en fin d'animation, sa vitesse de dplacement va fortement s'altrer jusqu' arriver destination, le nord. Nous pouvons donc remplacer notre portion de code par ceci : CompassView.java
if (totalTime > DURATION) { ? } else { float perCent = ((float) totalTime) / DURATION; // Animation plus raliste de l'aiguille perCent = (float) Math.sin(perCent * 1.5); perCent = Math.min(perCent, 1); northOrientation = (float) (startNorthOrientation + perCent * (endNorthOrientation startNorthOrientation)); postDelayed(this, DELAY);

} // Quoi qu'il arrive, on demande notre vue de se redessiner invalidate();

V-D - Forcer le sens de rotation de l'aiguille


Nous voici donc en prsence d'une jolie boussole dont le comportement est proche de celui d'une vraie boussole, cependant, notre animation possde toujours un "bug", ou plutt une raction trange. Par exemple, lorsqu'elle passe de l'orientation 5 350 celle-ci dcide d'emprunter le chemin suivant :

Rotation non raliste Il va nous faudra donc forcer le sens d'volution de notre aiguille, en augmentant par exemple, de manire virtuelle, l'orientation de dpart ou d'arrive de 360. Si nous reprenons le cas de l'exemple prcdent, nous augmenterons de 360 la position de dpart qui devient 365. Ainsi notre aiguille, voluant entre 365 et 350, empruntera le chemin le plus court, qui se trouve galement tre le plus raliste. Voici les modifications apportes la mthode SetNorthOrientation :

- 15 Copyright 2010 - Davy Leggieri. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://davy-leggieri.developpez.com/tutoriels/android/creation-boussole/

Cration d'une boussole par Davy Leggieri (Page de l'auteur)

CompassView.java
// permet de changer l'orientation de la boussole public void setNorthOrientation(float rotation) { // on met jour l'orientation uniquement si elle a chang if (rotation != this.northOrientation) { //Arrter l'ancienne animation removeCallbacks(animationTask); //Position courante this.startNorthOrientation = this.northOrientation; //Position dsire this.endNorthOrientation = rotation; //Dtermination du sens de rotation de l'aiguille if ( ((startNorthOrientation + 180) % 360) > endNorthOrientation) { //Rotation vers la gauche if ( (startNorthOrientation - endNorthOrientation) > 180 ) { endNorthOrientation+=360; } } else { //Rotation vers la droite if ( (endNorthOrientation - startNorthOrientation) > 180 ) { startNorthOrientation+=360; } } //Nouvelle animation startTime = SystemClock.uptimeMillis(); postDelayed(animationTask, DELAY);

A prsent, nous allons simplifier la valeur de l'orientation lorsque l'on atteint la position finale, tout simplement car l'astuce utilise juste ci-dessus gnre des valeurs suprieures 360, c'est--dire, plus d'un tour de cadran, ce qui est quelque peu gnant. CompassView.java
private Runnable animationTask = new Runnable() { public void run() { ? if (totalTime > DURATION) { northOrientation = endNorthOrientation % 360; removeCallbacks(animationTask); } else { ? } ? } };

V-E - Critique
Je tiens apporter une critique l'animation que nous avons produite. Le rsultat est satisfaisant d'autant plus s'il s'agit de vos premiers pas, mais il reste amliorable. Pour comprendre pourquoi l'animation est perfectible, je tiens revenir au fonctionnement de la boussole numrique et plus particulirement au listener qui est li au changement d'orientation. Lorsque vous tournez votre tlphone mobile, ce dernier ne change pas brusquement d'orientation mais dtecte plusieurs tats intermdiaires. Par consquent, notre programme se voit dlivrer x fois par seconde une nouvelle orientation. Vous comprendrez donc que, dans ces conditions, notre animation s'talant sur une seconde, elle soit prise de court et ne peut se terminer compltement. Visuellement cela n'a que peu d'importance car la fin de l'animation est provoque par l'arrive d'une nouvelle orientation qui induit le dbut d'une nouvelle animation.
- 16 Copyright 2010 - Davy Leggieri. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://davy-leggieri.developpez.com/tutoriels/android/creation-boussole/

Cration d'une boussole par Davy Leggieri (Page de l'auteur)

Une approche envisageable serait de ne plus faire voluer l'orientation de notre aiguille entre une position de dpart et celle d'arrive, mais plutt d'attribuer une vitesse de rotation notre aiguille en fonction de sa distance par rapport au nord. Le rsultat sera plus facilement prvisible et contrlable, ainsi nous serons en adquation avec la raction relle d'une boussole.

VI - Conclusion
La cration d'une vue sous Android est assez simple. Il suffit de redfinir les mthodes onDraw et onMeasure. L'alimentation de celle-ci grce aux donnes issues des capteurs est possible grce aux SensorEventListener. L'animation par contre recours des handlers qui dterminent le pourcentage d'volution de l'animation et redessinent la vue. En guise de conclusion ce tutoriel, je vais revenir sur le choix de la boussole. Le rsultat est une boussole ragissant en fonction de l'orientation de votre tlphone portable la manire d'une boussole relle. Mise part le rsultat assez plaisant et amusant, le choix de cette ralisation ne fut qu'un prtexte permettant de vous prsenter la cration et l'animation de vues. J'espre tout simplement avoir rempli ma mission.

VII - Remerciements
Je tiens remercier les membres de l'quipe de Developpez.com, pixelomilcouleurs, jacques_jean, Kvin F. et Thomas G. pour leur aide la relecture de ce tutoriel.

VIII - Liens
Voici les liens pour tlcharger le code source et le package Android : Code source - (Miroir) Package Android- (Miroir)

- 17 Copyright 2010 - Davy Leggieri. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://davy-leggieri.developpez.com/tutoriels/android/creation-boussole/

You might also like