Encore plus de widgets et de conteneurs



Documents pareils
TP SIN Programmation sur androïde Support : eclipse

Outils, langage et approche Android Une introduction. Nicolas Stouls lyon.fr

SOMMAIRE

Programmation des applications mobiles avec Android. 1 Inspiré du cours de Olivier Le Goaer

TP2 : Client d une BDD SqlServer

Warren PAULUS. Android SDK et Android x86

TP au menu «UI ANDROID»

Créer des applications Android

Génie Logiciel et Interaction Homme-Machine PROJET UCAMPUS

Développement Android. J.-F. Couchot

Android 4 Les fondamentaux du développement d'applications Java

Gestion des différentes tailles d écran

De Java à Android version 0.1

Les fondamentaux du développement d applications Java

Tutoriel. Votre site web en 30 minutes

1.3 Gestion d'une application

Table des matières. Partie I Concepts de base Préface... VII

ContactForm et ContactFormLight - Gestionnaires de formulaire pour Prestashop Edité par ARETMIC S.A.

PRISE EN MAIN D UN TABLEUR. Version OPEN OFFICE

L ARBORESCENCE. Qu est-ce qu un dossier? L arborescence?

Comment réaliser une capture d écran dans Word. Alors comment ouvrir une page Word?

SOMMAIRE. 1. Connexion à la messagerie Zimbra Pré-requis Ecran de connexion à la messagerie 4

Sélection du contrôleur

Afin d accéder à votre messagerie personnelle, vous devez vous identifier par votre adresse mail et votre mot de passe :

Avant-propos FICHES PRATIQUES EXERCICES DE PRISE EN MAIN CAS PRATIQUES

Introduction ANDROID

Vous allez le voir au cours de ce premier chapitre, 1. Découvrir l ipad

TP1 : Initiation à Java et Eclipse

v Sygic, a.s. All rights reserverd. Manuel utilisateur

Programmation Android L3 informatique

< Atelier 1 /> Démarrer une application web

Android. Programmation. De la conception au déploiement avec le SDK Google Android 2. Damien Guignard Julien Chable Emmanuel Robles

Tutorial pour une application simple

Début de la procédure

Module 1 : Tableau de bord Excel * 2010 incl.*

Développement d'applications pour Android. M. Dalmau IUT de Bayonne Pays Basque

Installation et utilisation du client FirstClass 11

Fiche Mémo : Options d accessibilité sous Windows et Internet Explorer 5

Manuel d utilisation 26 juin Tâche à effectuer : écrire un algorithme 2

Atelier Formation Pages sur ipad Pages sur ipad

Utilisation d une tablette numérique 01 Initiation à l utilisation de l ipad

Débuter avec Excel. Excel

Trucs et Astuces Outlook 2010 SIFA Faculté d Administration

Guide d utilisation du logiciel TdsTexto 1.0

COURS WINDEV NUMERO 3

Résumé succinct des fonctions de messagerie électronique

[WINDOWS 7 - LES FICHIERS] 28 avril Logiciel / Windows

L espace de travail de Photoshop

FICHIERS ET DOSSIERS

Ouvrir le compte UQÀM

SOMMAIRE ÉTAPES OBLIGATOIRES. Récupérer le connecteur... 3

sommaire ÉTAPES OBLIGATOIRES Récupérer le connecteur... 3

WINDOWS 8. Windows 8 se distingue par la présence de 2 interfaces complémentaires :

Silhouette Studio Leçon N 2

On trouvera sur le site du CCDMD un exemple d album construit avec Cantare. (

Infolettre #18 : Les graphiques avec Excel 2010

Votre premier projet Android

PROCÉDURE D AIDE AU PARAMÉTRAGE

L environnement de travail de Windows 8

Premiers Pas en Programmation Objet : les Classes et les Objets

LES TABLETTES : EN PRATIQUE

Formation. Module WEB 4.1. Support de cours

Gestion des réunions dans Outlook 2007

Organiser le disque dur Dossiers Fichiers

Projet Android (LI260) Cours 2

ET 24 : Modèle de comportement d un système Boucles de programmation avec Labview.

Optimiser pour les appareils mobiles

La Clé informatique. Formation Excel XP Aide-mémoire

TD/TP 1 Introduction au SDK d Android

Ouvrez un compte Hotmail pour communiquer

Eclipse atelier Java

Découvrir la messagerie électronique et communiquer entre collègues. Entrer dans le programme Microsoft Outlook Web Access

MO-Call pour les Ordinateurs. Guide de l utilisateur

CARPE. Documentation Informatique S E T R A. Version Août CARPE (Documentation Informatique) 1

Guide d utilisation du ipad

STRUCTURE DE L ORDINATEUR

Numbers sur ipad. Atelier Formation Numbers sur ipad. [Notes extraitres de l'aide en ligne]

Création d un formulaire de contact Procédure

Programmation mobile avec Android

Table des matières. 7 Gérer des ordres 5 Formater des paramètres OptionStation Pro 9

Tutoriel Atout Facture. 14/01/2015 Codelpi

CREG : versailles.fr/spip.php?article803

LES TOUT PREMIERS PAS

Pour signifier qu'une classe fille hérite d'une classe mère, on utilise le mot clé extends class fille extends mère

Créer sa première base de données Access Partie 4/4 - Création d un état

Le poste de travail, les dossiers et les fichiers

Guide de configuration. Logiciel de courriel

Cahier n o 6. Mon ordinateur. Fichiers et dossiers Sauvegarde et classement

Date M.P Libellé Catégorie S.Catégorie Crédit Débit Solde S.B

Tutoriel Android. Pour démarrer la programmation d'applications Android

Premiers Pas avec OneNote 2013

Séminaire d information MIGRATION WINDOWS 7 ET OFFICE 2010

MetaTrader 4/5 pour Android. Guide de l utilisateur

Tutoriel Android - TP de prise en main

VOCABULAIRE LIÉ AUX ORDINATEURS ET À INTERNET

Niveau 1. Atelier d'initiation à l'ordinateur ... Fondation de la Bibliothèque Memphrémagog inc. Magog (Québec) J1X 2E7 Tél.

Manuel d utilisation NETexcom

1 CRÉER UN TABLEAU. IADE Outils et Méthodes de gestion de l information

Manuel d utilisation du site web de l ONRN

Transcription:

14 Encore plus de widgets et de conteneurs Nous avons déjà présenté un certain nombre de widgets et de conteneurs, et ce chapitre sera le dernier qui leur sera exclusivement consacré : il présente plusieurs widgets souvent utilisés dans les applications, comme les widgets pour la date et l heure, les onglets, etc. Après ce chapitre, nous découvrirons encore de nouveaux widgets, mais uniquement dans le contexte d un autre sujet, comme la présentation de ProgressBar au Chapitre 20 (qui est consacré aux threads). Choisir Avec des terminaux ayant des capacités de saisie limitées comme les téléphones, il est très utile de disposer de widgets et de boîtes de dialogue capables d anticiper ce que l utilisateur veut taper. Cela minimise le nombre de frappes au clavier et de touches à l écran et réduit les risques d erreur (la saisie d une lettre à la place d un chiffre, par exemple). Comme on l a mentionné au Chapitre 9, EditText possède des variantes permettant de saisir des nombres ou du texte. Android dispose également de widgets (DatePicker, TimePicker) et de dialogues (DatePickerDialog, TimePickerDialog) facilitant la saisie des dates et des heures. DatePicker et DatePickerDialog permettent de fixer une date de départ, sous la forme d une année, d un mois et d un jour. Les mois vont de 0 (janvier) à 11 (décembre). Tous les deux permettent de préciser un écouteur (OnDateChangedListener ou OnDateSetListener) pour vous informer qu une nouvelle date a été choisie. Il vous appartient de stocker cette date quelque part, notamment si vous utilisez la boîte de dialogue, car vous n aurez pas d autre moyen de la récupérer ensuite. De même, TimePicker et TimePickerDialog permettent : De fixer l heure initiale, que l utilisateur peut ensuite ajuster sous la forme d une heure (de 0 à 23) et de minutes (de 0 à 59).

138 L'Art du développement Android D indiquer si le format de la date choisi utilise le mode sur 12 heures avec un indicateur AM/PM ou le mode 24 heures (ce qui, aux États-Unis, est appelé "temps militaire" et qui est le mode utilisé partout ailleurs dans le monde). De fournir un écouteur (OnTimeChangedListener ou OnTimeSetListener) pour être prévenu du choix d une nouvelle heure, qui vous sera fournie sous la forme d une heure et de minutes. Le projet Fancy/Chrono, par exemple, utilise une disposition très simple, formée d un label et de deux boutons qui feront surgir les boîtes de dialogue pour choisir une date et une heure : <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_height="fill_parent" > <TextView android:id="@+id/dateandtime" android:layout_height="wrap_content" <Button android:id="@+id/datebtn" android:layout_height="wrap_content" android:text="choisir une date" android:onclick="choosedate" <Button android:id="@+id/timebtn" android:layout_height="wrap_content" android:text="choisir une heure" android:onclick="choosetime" </LinearLayout> La partie intéressante se trouve dans le code Java : package com.commonsware.android.chrono; import android.app.activity; import android.os.bundle; import android.app.datepickerdialog; import android.app.timepickerdialog; import android.view.view; import android.widget.datepicker; import android.widget.timepicker; import android.widget.textview;

Chapitre 14 Encore plus de widgets et de conteneurs 139 import java.text.dateformat; import java.util.calendar; public class ChronoDemo extends Activity { DateFormat fmtdateandtime=dateformat.getdatetimeinstance(); TextView dateandtimelabel; Calendar dateandtime=calendar.getinstance(); @Override public void oncreate(bundle icicle) { super.oncreate(icicle); setcontentview(r.layout.main); dateandtimelabel=(textview)findviewbyid(r.id.dateandtime); updatelabel(); public void choosedate(view v) { new DatePickerDialog(ChronoDemo.this, d, dateandtime.get(calendar.year), dateandtime.get(calendar.month), dateandtime.get(calendar.day_of_month)).show(); public void choosetime(view v) { new TimePickerDialog(ChronoDemo.this, t, dateandtime.get(calendar.hour_of_day), dateandtime.get(calendar.minute), true).show(); private void updatelabel() { dateandtimelabel.settext(fmtdateandtime.format(dateandtime.gettime())); DatePickerDialog.OnDateSetListener d= new DatePickerDialog.OnDateSetListener() { public void ondateset(datepicker view, int year, int monthofyear, int dayofmonth) { dateandtime.set(calendar.year, year); dateandtime.set(calendar.month, monthofyear); dateandtime.set(calendar.day_of_month, dayofmonth); updatelabel(); ;

140 L'Art du développement Android TimePickerDialog.OnTimeSetListener t= new TimePickerDialog.OnTimeSetListener() { public void ontimeset(timepicker view, int hourofday, int minute) { dateandtime.set(calendar.hour_of_day, hourofday); dateandtime.set(calendar.minute, minute); updatelabel(); ; Le "modèle" de cette activité est simplement une instance de Calendar initialisée avec la date et l heure courantes et placée dans la vue via un formateur DateFormat. La méthode updatelabel() prend le Calendar courant, le formate et le place dans le TextView correspondant au label. Chaque bouton est associé à une méthode qui s exécutera lorsque l utilisateur cliquera dessus (choosedate() et choosetime()). Lorsqu on clique sur le bouton, une boîte de dialogue DatePickerDialog ou TimePickerDialog s affiche. Dans le cas de DatePickerDialog, on lui passe un écouteur OnDateSetListener pour mettre à jour le Calendar avec la nouvelle date (année, mois, jour). On lui passe également la dernière date choisie, en récupérant les valeurs qui se trouvent dans le Calendar. TimePickerDialog, quant à lui, reçoit un écouteur OnTimeSetListener pour mettre à jour la portion horaire du Calendar ; on lui passe également la dernière heure choisie et true pour indiquer que l on veut un format sur 24 heures. Le résultat de cette activité est présenté aux Figures 14.1, 14.2 et 14.3. Figure 14.1 L application ChronoDemo lors de son lancement.

Chapitre 14 Encore plus de widgets et de conteneurs 141 Figure 14.2 La même application, montrant le dialogue de choix de la date. Figure 14.3 La même application, montrant le dialogue de choix de l heure.

142 L'Art du développement Android Le temps s écoule comme un fleuve Pour afficher l heure sans autoriser les utilisateurs à la modifier, utilisez les widgets DigitalClock ou AnalogClock. Il suffit simplement de les placer dans votre layout et de les laisser travailler. Le fichier main.xml du projet Fancy/Clocks contient ces deux widgets : <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_height="fill_parent" > <AnalogClock android:id="@+id/analog" android:layout_height="wrap_content" android:layout_centerhorizontal="true" android:layout_alignparenttop="true" <DigitalClock android:id="@+id/digital" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerhorizontal="true" android:layout_below="@id/analog" </RelativeLayout> Sans avoir besoin de modifier quoi que ce soit au squelette de code Java produit automatiquement, on obtient l application présentée à la Figure 14.4. Figure 14.4 L application ClocksDemo.

Chapitre 14 Encore plus de widgets et de conteneurs 143 Si vous recherchez plutôt un chronomètre, le widget Chronometer est fait pour vous car il permet de mémoriser le temps écoulé à partir d un point de départ : il suffit de lui dire quand démarrer (start()), s arrêter (stop()) et, éventuellement, de redéfinir le format de la chaîne de texte affichée. La Figure 14.5 montre le résultat obtenu. Figure 14.5 La démo de l API Views/Chronometer du SDK Android 2.0. Prendre la bonne résolution La classe SeekBar est un widget qui permet à l utilisateur de saisir une valeur prise dans un intervalle donné. La Figure 14.6 montre ce qu affiche l exemple fourni avec le SDK d Android 2.0. Figure 14.6 La démo de l API Views/SeekBar du SDK Android 2.0.

144 L'Art du développement Android L utilisateur peut faire glisser le curseur ou cliquer sur l un des deux côtés pour le repositionner. Ce curseur désigne en réalité une valeur dans un intervalle déterminé 0 à 100 par défaut, mais vous pouvez modifier la borne supérieure par un appel à setmax(). La méthode getprogress() renvoie la position courante et l enregistrement d un écouteur à l aide de setonseekbarchangelistener() permet d être prévenu de toute modification du curseur. L exemple RatingBar que nous avons étudié au Chapitre 13 était une variante de ce widget. Utilisation d onglets La philosophie générale d Android consiste à faire en sorte que les activités soient courtes et agréables. Lorsqu il y a plus d informations que ne peut raisonnablement en contenir l écran (bien que l on puisse utiliser des barres de défilement), il peut être préférable de produire ces informations supplémentaires par une autre activité, lancée via une Intent, comme on l explique au Chapitre 22. Cependant, ceci peut être assez compliqué à mettre en place. En outre, il arrive parfois que l on doive recueillir et traiter beaucoup d informations en une seule opération. Dans une interface graphique classique, nous pourrions utiliser des onglets à cette fin, comme un JTabbedPane en Java/Swing. Avec Android, on dispose désormais d un conteneur TabHost qui fonctionne exactement de la même façon une portion de ce qu affiche l activité est liée à des onglets qui, lorsque l on clique dessus, permettent de passer d une partie de la vue à une autre. Une activité utilisera par exemple un onglet pour la saisie d un emplacement et un autre pour afficher cet emplacement sur une carte. Certains kits de développement considèrent simplement les onglets comme des objets cliquables, permettant de passer d une vue à l autre. D autres les considèrent comme une combinaison de l élément cliquable et du contenu qui apparaît lorsque l on clique dessus. Avec Android, les boutons et les contenus des onglets étant des entités distinctes, nous emploierons les termes "bouton de l onglet" et "contenu de l onglet" dans cette section. Les pièces du puzzle Pour mettre en place des onglets dans une vue, vous avez besoin des widgets et des conteneurs suivants : TabHost est le conteneur général pour les boutons et les contenus des onglets. TabWidget implémente la ligne des boutons des onglets, qui contient les labels et, éventuellement, des icônes.

Chapitre 14 Encore plus de widgets et de conteneurs 145 FrameLayout est le conteneur des contenus des onglets : chaque contenu d onglet est un fils du FrameLayout. Cette approche ressemble à celle de XUL de Mozilla : les éléments tabbox, tabs et tabpanels de XUL correspondent respectivement à TabHost, TabWidget et FrameLayout. Voici le fichier de description d une activité utilisant des onglets, tiré du projet Fancy/Tab : <?xml version="1.0" encoding="utf-8"?> <TabHost xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/tabhost" android:layout_height="fill_parent"> <LinearLayout android:orientation="vertical" android:layout_height="fill_parent"> <TabWidget android:id="@android:id/tabs" android:layout_height="wrap_content" <FrameLayout android:id="@android:id/tabcontent" android:layout_height="fill_parent"> <AnalogClock android:id="@+id/tab1" android:layout_height="fill_parent" <Button android:id="@+id/tab2" android:layout_height="fill_parent" android:text="bouton presque aléatoire" </FrameLayout> </LinearLayout> </TabHost> Vous remarquerez que les éléments TabWidget et FrameLayout sont des fils indirects de TabHost et que l élément FrameLayout a lui-même un fils représentant les différents onglets. Ici, il y en a deux : une horloge et un bouton. Dans un scénario plus compliqué, les onglets seraient regroupés dans un conteneur (un LinearLayout, par exemple) avec leurs propres contenus. Tout câbler Vous pouvez placer ces widgets dans une Activity normale ou dans une TabActivity. Cette dernière, comme ListActivity, enveloppe un patron d interface graphique classique (une activité composée entièrement d onglets) dans une

146 L'Art du développement Android sous-classe d activité. Pour utiliser TabActivity, vous devez donner au TabHost l identifiant @android:id/tabhost. Inversement, si vous ne souhaitez pas l utiliser, vous devez obtenir le TabHost via un appel à findviewbyid() puis appeler setup() sur le TabHost avant de faire quoi que ce soit d autre. Le reste du code Java doit indiquer au TabHost quelles sont les vues qui représentent les contenus des onglets et à quoi doivent ressembler les boutons de ces onglets. Tout ceci est encapsulé dans des objets TabSpec. On récupère une instance de TabSpec via la méthode newtabspec() du TabHost, on la remplit puis on l ajoute au TabHost dans le bon ordre. Les deux méthodes essentielles de TabSpec sont les suivantes : setcontent(), qui permet d indiquer le contenu de cet onglet. Généralement, il s agit de l identifiant android:id de la vue que l on veut montrer lorsque l onglet est choisi. setindicator(), qui permet de fournir le titre du bouton de l onglet. Cette méthode est surchargée pour permettre de fournir également un objet Drawable représentant l icône de l onglet. Notez que les "indicateurs" des onglets peuvent, en fait, être eux-mêmes des vues, ce qui permet de faire mieux qu un simple label et une icône facultative. Notez également que vous devez appeler la méthode setup() de l objet TabHost avant de configurer les objets TabSpec. Cet appel n est pas nécessaire si votre activité dérive de la classe de base TabActivity. Voici, par exemple, le code Java permettant de faire fonctionner les onglets de la section précédente : package com.commonsware.android.fancy; import android.app.activity; import android.os.bundle; import android.widget.tabhost; public class TabDemo extends Activity { @Override public void oncreate(bundle icicle) { super.oncreate(icicle); setcontentview(r.layout.main); TabHost tabs=(tabhost)findviewbyid(r.id.tabhost); tabs.setup(); TabHost.TabSpec spec=tabs.newtabspec("tag1");

Chapitre 14 Encore plus de widgets et de conteneurs 147 spec.setcontent(r.id.tab1); spec.setindicator("heure"); tabs.addtab(spec); spec=tabs.newtabspec("tag2"); spec.setcontent(r.id.tab2); spec.setindicator("bouton"); tabs.addtab(spec); tabs.setcurrenttab(0); On retrouve notre TabHost via un appel à la méthode findviewbyid(), puis on appelle sa méthode setup(). On crée ensuite une instance de TabSpec via un appel à newtabspec() auquel on passe un marqueur dont le but est encore inconnu. On appelle les méthodes setcontent() et setindicator() de cette instance, puis la méthode addtab() de l objet TabHost pour lui ajouter le TabSpec. Enfin, on choisit l onglet qui s affichera initialement, à l aide de la méthode setcurrenttab() (la valeur 0 désigne le premier onglet). Les Figures 14.7 et 14.8 montrent ce qu affiche cette application. Figure 14.7 L application TabDemo affichant son premier onglet.

148 L'Art du développement Android Figure 14.8 La même application affichant son second onglet. Ajouts dynamiques TabWidget est configuré pour simplifier la définition des onglets au moment de la compilation. Cependant, vous voudrez parfois créer des onglets au cours de l exécution de votre activité. Imaginons, par exemple, un client de courrier où les différents e-mails s ouvrent dans leurs propres onglets, afin de faciliter le passage d un message à l autre. Dans cette situation, vous ne pouvez pas savoir à l avance le nombre d onglets ni leur contenu : vous devez attendre que l utilisateur ouvre un message de courrier. Heureusement, Android permet également d ajouter dynamiquement des onglets en cours d exécution. Cet ajout fonctionne exactement comme on vient de le voir, sauf qu il faut utiliser une autre variante de setcontent() qui prend en paramètre une instance de TabHost, TabContentFactory, qui est simplement une méthode de rappel qui sera appelée automatiquement : il suffit de fournir une implémentation de createtabcontent() et de l utiliser pour construire et renvoyer la vue qui deviendra le contenu de l onglet. Cette approche est présentée dans le projet Fancy/DynamicTab. La description de l interface de l activité met en place les onglets et n en définit qu un seul, contenant un simple bouton : <?xml version="1.0" encoding="utf-8"?> <TabHost xmlns:android="http://schemas.android.com/apk/res/android"

Chapitre 14 Encore plus de widgets et de conteneurs 149 android:id="@+id/tabhost" android:layout_height="fill_parent"> <LinearLayout android:orientation="vertical" android:layout_height="fill_parent"> <TabWidget android:id="@android:id/tabs" android:layout_height="wrap_content" <FrameLayout android:id="@android:id/tabcontent" android:layout_height="fill_parent"> <Button android:id="@+id/buttontab" android:layout_height="fill_parent" android:text="bouton presque aléatoire" android:onclick="addtab" </FrameLayout> </LinearLayout> </TabHost> Nous voulons maintenant ajouter de nouveaux onglets à mesure que l on clique sur ce bouton, ce qui se réalise en quelques lignes de code : package com.commonsware.android.dynamictab; import android.app.activity; import android.os.bundle; import android.view.view; import android.widget.analogclock; import android.widget.tabhost; public class DynamicTabDemo extends Activity { private TabHost tabs=null; @Override public void oncreate(bundle icicle) { super.oncreate(icicle); setcontentview(r.layout.main); tabs=(tabhost)findviewbyid(r.id.tabhost); tabs.setup(); TabHost.TabSpec spec=tabs.newtabspec("buttontab"); spec.setcontent(r.id.buttontab); spec.setindicator("bouton"); tabs.addtab(spec);

150 L'Art du développement Android public void addtab(view v) { TabHost.TabSpec spec=tabs.newtabspec("tag1"); spec.setcontent(new TabHost.TabContentFactory() { public View createtabcontent(string tag) { return(new AnalogClock(DynamicTabDemo.this)); ); ); spec.setindicator("heure"); tabs.addtab(spec); On crée un objet TabHost.TabSpec dans la méthode de rappel addtab() de notre bouton en lui passant en paramètre une fabrique TabHost.TabContentFactory anonyme. Cette fabrique, à son tour, renvoie la vue qui sera utilisée pour l onglet ici un AnalogClock. Le code de construction de cette vue pourrait être bien plus élaboré et utiliser, par exemple, un LayoutInflater pour créer une vue à partir d un fichier de description XML. La Figure 14.9 montre que l activité n affiche qu un seul onglet lorsqu elle est lancée. La Figure 14.10 montre trois onglets, créés en cours d exécution. Figure 14.9 L application DynamicTabDemo avec son unique onglet initial.

Chapitre 14 Encore plus de widgets et de conteneurs 151 Figure 14.10 La même application, après la création de trois onglets en cours d exécution. Tout faire basculer Parfois, on souhaite bénéficier de l avantage des onglets (ne voir que certaines vues à la fois) sans pour autant utiliser leur présentation graphique (parce que, par exemple, les onglets prennent trop de place à l écran). On peut ainsi préférer passer d une vue à l autre par un mouvement du doigt sur l écran ou en secouant le terminal. La bonne nouvelle est que le mécanisme interne des onglets pour basculer entre les vues est disponible dans le conteneur ViewFlipper, qui peut être utilisé différemment d un onglet traditionnel. ViewFlipper hérite de FrameLayout, que nous avons utilisé plus haut pour décrire le fonctionnement interne d un TabWidget. Cependant, il ne montre que la première vue fille au départ : c est à vous qu il appartient de mettre en place le basculement entre les vues, soit manuellement par une action de l utilisateur, soit automatiquement par un timer. Voici, par exemple, le fichier de description du projet Fancy/Flipper1, qui utilise un Button et un ViewFlipper : <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

152 L'Art du développement Android android:orientation="vertical" android:layout_height="fill_parent" > <Button android:id="@+id/flip_me" android:layout_height="wrap_content" android:text="bascule moi!" android:onclick="flip" <ViewFlipper android:id="@+id/details" android:layout_height="fill_parent" > <TextView android:layout_height="wrap_content" android:textstyle="bold" android:textcolor="#ff00ff00" android:text="premier panneau" <TextView android:layout_height="wrap_content" android:textstyle="bold" android:textcolor="#ffff0000" android:text="second panneau" <TextView android:layout_height="wrap_content" android:textstyle="bold" android:textcolor="#ffffff00" android:text="troisieme panneau" </ViewFlipper> </LinearLayout> Ce layout définit trois vues filles de ViewFlipper, chacune étant un TextView contenant un simple message. Vous pourriez évidemment choisir des vues plus complexes. Pour basculer manuellement entre les vues, nous devons ajouter un écouteur au bouton pour que le basculement ait lieu lorsqu on clique dessus : package com.commonsware.android.flipper1; import android.app.activity; import android.os.bundle; import android.view.view; import android.widget.viewflipper;

Chapitre 14 Encore plus de widgets et de conteneurs 153 public class FlipperDemo extends Activity { ViewFlipper flipper; @Override public void oncreate(bundle icicle) { super.oncreate(icicle); setcontentview(r.layout.main); flipper=(viewflipper)findviewbyid(r.id.details); public void flip(view v) { flipper.shownext(); Il s agit simplement d appeler la méthode shownext() de ViewFlipper, comme pour n importe quelle classe ViewAnimator. Le résultat est une activité très simple : un clic sur le bouton fait apparaître le TextView suivant, en rebouclant sur le premier lorsqu ils se sont tous affichés (voir Figures 14.11 et 14.12). Figure 14.11 L application Flipper1 montant le premier panneau.

154 L'Art du développement Android Figure 14.12 La même application, après basculement vers le second panneau. Nous pourrions bien sûr gérer tout cela plus simplement en utilisant un seul TextView et en modifiant son texte et sa couleur à chaque clic. Cependant, vous pouvez imaginer que le contenu du ViewFlipper pourrait être bien plus compliqué inclure, par exemple, tout ce que l on peut mettre dans un TabView. Comme pour un TabWidget, le contenu d un ViewFlipper peut ne pas être connu lors de la compilation et, comme pour un TabWidget, il est relativement simple d ajouter du contenu à la volée. Voici, par exemple, le layout d une autre activité, celle du projet Fancy/Flipper2 : <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_height="fill_parent" > <ViewFlipper android:id="@+id/details" android:layout_height="fill_parent" > </ViewFlipper> </LinearLayout>

Chapitre 14 Encore plus de widgets et de conteneurs 155 Vous remarquerez que l élément ViewFlipper n a aucun contenu au moment de la compilation. Notez également qu il n y a pas de bouton pour basculer entre les contenus nous reviendrons sur ce point dans un instant. Pour le contenu du ViewFlipper, nous créerons de gros boutons contenant, chacun, un ensemble de mots quelconques. Nous configurerons également le ViewFlipper pour qu il boucle automatiquement sur ces widgets Button : package com.commonsware.android.flipper2; import android.app.activity; import android.os.bundle; import android.view.view; import android.view.viewgroup; import android.widget.button; import android.widget.viewflipper; public class FlipperDemo2 extends Activity { static String[] items={"lorem", "ipsum", "dolor", "sit", "amet", "consectetuer", "adipiscing", "elit", "morbi", "vel", "ligula", "vitae", "arcu", "aliquet", "mollis", "etiam", "vel", "erat", "placerat", "ante", "porttitor", "sodales", "pellentesque", "augue", "purus"; ViewFlipper flipper; @Override public void oncreate(bundle icicle) { super.oncreate(icicle); setcontentview(r.layout.main); flipper=(viewflipper)findviewbyid(r.id.details); for (String item : items) { Button btn=new Button(this); btn.settext(item); flipper.addview(btn, new ViewGroup.LayoutParams( ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); flipper.setflipinterval(2000); flipper.startflipping();

156 L'Art du développement Android Après avoir parcouru tous les mots en les transformant en autant de boutons fils de l objet ViewFlipper, nous configurons ce dernier pour qu il bascule automatiquement entre ses fils (flipper.setflipinterval(2000);) et nous lançons le basculement (flipper.startflipping();). Le résultat est une suite sans fin de boutons qui apparaissent puis sont remplacés à chaque fois par le bouton suivant de la séquence après un délai de 2 secondes (voir Figure 14.13). L ensemble revient au premier bouton après la disparition du dernier. Figure 14.13 L application Flipper2. Ce basculement automatique est utile pour les panneaux d information ou les autres situations dans lesquelles vous voulez afficher beaucoup d informations dans un espace réduit. Ces différentes vues basculant automatiquement de l une à l autre, il serait risqué de demander aux utilisateurs d interagir avec elles une vue pourrait disparaître au milieu d une interaction. Fouiller dans les tiroirs Depuis longtemps, les développeurs Android réclamaient un conteneur de type tiroir, fonctionnant comme celui de l écran d accueil, qui contient les icônes pour lancer les applications. L implémentation officielle existait dans le code open-source mais n était pas intégrée dans le SDK... jusqu à Android 1.5, qui a fourni le widget SlidingDrawer.

Chapitre 14 Encore plus de widgets et de conteneurs 157 À la différence de la plupart des autres conteneurs, SlidingDrawer change d aspect puisqu il passe d une position fermée à une position ouverte. Cette caractéristique implique quelques restrictions sur le conteneur dans lequel peut se trouver le SlidingDrawer puisqu il doit permettre à plusieurs widgets de cohabiter les uns au-dessus des autres. RelativeLayout et FrameLayout satisfont cette exigence FrameLayout est un conteneur conçu spécialement pour empiler les widgets les uns sur les autres. LinearLayout, en revanche, ne permet pas d empiler des widgets (ils sont placés les uns après les autres, en ligne ou en colonne), c est la raison pour laquelle un SlidingDrawer ne doit pas être un fils direct d un élément LinearLayout. Voici un exemple tiré du projet Fancy/DrawerDemo, avec un SlidingDrawer placé dans un FrameLayout : <?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_height="fill_parent" android:background="#ff4444cc" > <SlidingDrawer android:id="@+id/drawer" android:layout_height="fill_parent" android:handle="@+id/handle" android:content="@+id/content"> <ImageView android:id="@id/handle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/tray_handle_normal" <Button android:id="@id/content" android:layout_height="fill_parent" android:text="je suis dedans!" </SlidingDrawer> </FrameLayout> Le SlidingDrawer doit contenir : une poignée le plus souvent un ImageView, comme ici ; le contenu du tiroir lui-même généralement un conteneur, bien qu ici nous utilisions un bouton. En outre, SlidingDrawer doit connaître les valeurs android:id de la poignée et du contenu en les stockant, respectivement, dans ses attributs android:handle et android:content. Ceci permet au tiroir de savoir comment s animer lorsqu il s ouvre ou se ferme.

158 L'Art du développement Android La Figure 14.14 montre l aspect du tiroir fermé, avec la poignée qu on lui a f ournie. La Figure 14.15 montre le tiroir ouvert, avec son contenu. Figure 14.14 L application DrawerDemo avec son tiroir fermé. Figure 14.15 La même application avec le tiroir ouvert. Comme on pourrait s y attendre, on peut ouvrir et refermer le tiroir à partir du code Java ou par des événements de "touchés" utilisateurs. Il existe deux groupes de

Chapitre 14 Encore plus de widgets et de conteneurs 159 méthodes : les premières agissent instantanément (open(), close() et toggle()), les autres utilisent une animation (animateopen(), animateclose() et animatetoggle()). Le tiroir se verrouille avec lock() et se déverrouille avec unlock() ; lorsqu il est verrouillé, le tiroir ne répond pas aux touchés sur l écran. Vous pouvez également, si vous le souhaitez, enregistrer trois types de méthodes de rappel : un écouteur qui sera appelé lors de l ouverture du tiroir ; un écouteur qui sera appelé lors de la fermeture du tiroir ; un écouteur qui sera appelé lorsque le tiroir "défile" (c est-à-dire lorsque l utilisateur tire ou repousse la poignée). Le SlidingDrawer du lanceur, par exemple, change l icône de sa poignée pour qu elle signifie "ouvrir", "fermer" ou "supprimer" (lorsque l on touche pendant un certain temps une icône du bureau). Pour ce faire, il utilise notamment des méthodes de rappel comme celles que nous venons de citer. SlidingDrawer peut être vertical ou horizontal. Cependant, cette orientation reste identique quelle que soit celle de l écran : en d autres termes, si vous faites pivoter le terminal ou l émulateur pendant qu il exécute DrawerDemo, le tiroir s ouvrira toujours en partant du bas il ne "colle" pas toujours au bord par rapport à celui auquel il s est ouvert. Pour que le tiroir s ouvre toujours du même côté, comme le lanceur, vous aurez besoin de layouts différents pour le mode portrait et le mode paysage un sujet que nous aborderons au Chapitre 23. Autres conteneurs intéressants Android fournit également le conteneur AbsoluteLayout, dont le contenu est disposé en fonction de coordonnées spécifiques on lui indique où placer un fils en précisant ses coordonnées X, Y, et Android le positionne à cet endroit sans poser de question. Ceci a l avantage de fournir un positionnement précis ; en revanche, cela signifie également que les vues n auront un aspect correct que sur des écrans d une certaine dimension, à moins d écrire beaucoup de code pour ajuster les coordonnées en fonction de la taille de l écran. Les écrans Android pouvant avoir n importe quelle taille et ces tailles évoluant continuellement, l utilisation d AbsoluteLayout risque de devenir assez problématique. Note Officiellement, AbsoluteLayout est considéré comme obsolète : bien qu il reste disponible, il est désormais déconseillé de l utiliser.