Ce tutorial montre comment construire de manière dynamique une IHM android. Un article a été publié par l'auteur sur developpez.com pour en expliquer ce principe: Construction d'IHM Android dynamique
Cet article est aussi à votre disposition en bas de cette page, sous le lien de téléchargement.

Vous trouverez, dans le zip joint, le projet Eclipse montrant la mise en place de ces fonctionnalités prêt à être utilisé.
Ce code est libre de toute utilisation mais n'est pas distribuable.
Sa distribution et sa propriété intellectuelle est reservée au site
L’utilisation de ces codes est sous votre unique responsabilité et personne d’autre que vous ne pourra être tenu responsable des préjudices ou dommages de quelques natures que ce soit pouvant résulter de son utilisation.
Tous les noms de produits ou marques cités dans cet ouvrage sont des marques déposés par leurs propriétaires respectifs.Construction d'IHM Android dynamique
1. Introduction
2. Principe
3. Mise en place
3-1. Structure du projet
3-2. Du code par l'exemple
3-2-1. Les fichiers usuels de l'application
3-2-1-1. Le fichier AndroidManifest
3-2-2. Le fichier de layout
3-2-3. Destruction de la vue et son réaffichage
3-2-4. Gestion du placement des composants au sein des layouts
3-2-5. Gestion du Scroll
3-2-6. Gestion des composants usuels
3-2-7. Gestion des composants images
3-2-7-1. Cas d'une image contenue dans les ressources de l'application
3-2-7-1-1. La méthode getIdentifier
3-2-7-2. Cas d'une image provenant du web
3-2-8. Mise en place de données factices pour les tests
4. Récupération du tutoriel
5. Contact
6. Android2ee vous présente l'Ebook de programmation Android
7. Remerciements
1. Introduction
2. Principe
|
// Définition du Layout à construire.
LinearLayout postLayout = new LinearLayout( this );
// Définition du composant Text.
TextView txvName = new TextView( this );
txvName .setText(String. format (getString(R.string. wall_name ), post .getString( "name" )));
txvName .setTypeface(Typeface. defaultFromStyle (Typeface. BOLD ));
//Définition de la façon dont le composant va remplir le layout. LinearLayout.LayoutParams layoutParam = new LinearLayout.LayoutParams(LinearLayout.LayoutParams. FILL_PARENT , LinearLayout.LayoutParams. WRAP_CONTENT ) ;
//Ajout du composant au layout.
postLayout .addView( txvName , layoutParam );
|
|
//Tout d'abord, il faut détruire tous les éléments contenus dans le layout.
LinearLayout layoutOfDynamicContent = ( LinearLayout ) findViewById(R.id. layoutOfDynamicContent );
layoutOfDynamicContent .removeAllViewsInLayout();
//Ajouter les composants à ce layout. Votre IHM va être mise à jour.
|
Vous remarquerez que l’on ne détruit pas le layout, mais son contenu. C’est d’ailleurs ce contenu qui est entièrement reconstruit.
Enfin, un élément important à garder en tête est le cycle de vie de votre activité. Si vous ne mettez pas en place la sauvegarde de vos données lors des changements d’états (au sein des méthodes onPause, onResume), votre application rechargera entièrement les données à partir du serveur. Il vous faut donc être attentif à ce point.
3. Mise en place
3-1. Structure du projet
3-2. Du code par l'exemple
| Nom du champ | Type de la donnée |
| Titre | String |
| Description | String |
| Messages | List |
| FromWebPicture | Drawable |
Où l'objet Message est le suivant :
| Titre | String |
| Message | String |
| From | String |
| FromPicture | Drawable |
Les contraintes sont que la taille des listes est inconnue, seule la structure des données est connue par avance. De même les images sont à récupérer soit sur le web via leur URL, soit dans le dossier ressource\drawable de l'application.
3-2-1. Les fichiers usuels de l'application
3-2-1-1. Le fichier AndroidManifest
|
xml?> version = "1.0" encoding = "utf-8" PHP-->
< manifest xmlns:android = "http://schemas.android.com/apk/res/android"
package = "com.android2ee.tuto.gui"
android:versionCode = "1"
android:versionName = "1.0" >
< application android:icon = "@drawable/icon" android:label = "@string/app_name" >
< activity android:name = ".DynamicGui"
android:label = "@string/app_name" >
< intent-filter >
< action android:name = "android.intent.action.MAIN" />
< category android:name = "android.intent.category.LAUNCHER" />
intent-filter >
activity >
application > < uses-sdk android:minSdkVersion = "8" />
< uses-permission android:name = "android.permission.INTERNET" />
manifest >
|
3-2-2. Le fichier de layout
- le layout principal de l'activité ;
- un label affichant la chaine de caractères « Bonjour » ;
- un bouton permettant de relancer la construction dynamique de l'IHM ;
- et enfin, le layout qui contiendra la vue reconstruite dynamiquement.
|
xml version = "1.0" encoding = "utf-8" PHP-->
< LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android"
android:orientation = "vertical"
android:layout_width = "fill_parent"
android:layout_height = "fill_parent"
android:id = "@+id/mainlayout" >
< TextView android:layout_width = "fill_parent" android:layout_height = "wrap_content"
android:text = "@string/hello"
android:id = "@+id/txvHello" />
< Button android:text = "@string/reload" android:id = "@+id/btnReload"
android:layout_width = "wrap_content"
android:layout_height = "wrap_content" > Button >
< LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android" android:orientation = "vertical"
android:layout_width = "fill_parent"
android:layout_height = "fill_parent"
android:id = "@+id/layoutOfDynamicContent" >
LinearLayout >
LinearLayout >
|
3-2-3. Destruction de la vue et son réaffichage
|
//Tout d'abord, il faut détruire tous les éléments contenus dans le layout.
LinearLayout layoutOfDynamicContent = ( LinearLayout ) findViewById(R.id. layoutOfDynamicContent );
layoutOfDynamicContent .removeAllViewsInLayout();
//Ajouter les composants à ce layout. Votre IHM va être mise à jour.
//Cf. paragraphes suivants.
//Et c’est tout votre layout qui va être mis à jour automatiquement.
|
3-2-4. Gestion du placement des composants au sein des layouts
|
// Paramètres généraux du layout :
//Déclaration du layout et instanciation de celui-ci. LinearLayout lilPost = new LinearLayout( this );
//Définition de son orientation.
lilPost .setOrientation(LinearLayout. VERTICAL );
//Définition de son padding (le padding est la distance en pixels, entre le bord du composant et son contenu).
lilPost .setPadding(0, 15, 0, 0);
//Définition de la couleur de fond du layout.
lilPost .setBackgroundColor(0xFF007AAD);
.
.
// Paramètres spécifiques au placement du composant webPicture au sein du layout :
//Définition du paramètre de placement du composant au sein du layout et instanciation (avec la spécification de la manière dont le composant va remplir l'espace). LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams. WRAP_CONTENT , LinearLayout.LayoutParams. WRAP_CONTENT );
//Définition de la gravité du composant (comment il se positionne au sein de la zone qui lui est allouée).
params . gravity =Gravity. CENTER_HORIZONTAL ;
//Définition des marges du composant (distance, en pixels, autour du composant).
params .setMargins(5, 5, 5, 5);
//Ajout du composant dans le layout avec les paramètres de positionnement définis ci-dessus.
lilPost .addView( webPicture , params );
|
|
< LinearLayout android:id = "@+id/ lilPost "
android:orientation = " vertical "
android: paddingLeft = " 5 "
android: paddingRight = " 5 "
android: paddingTop = " 5 "
android: paddingBottom = " 5 "
android :background = " # 007AAD"
>
< ImageButton
android:id = "@+id/ webPicture "
android:layout_width = " wrap_content "
android:layout_height = " wrap_content "
android: layout_marginLeft = " 5 "
android: layout_marginRight = " 5 "
android: layout_marginTop = " 5 "
android: layout_marginBottom = " 5 "
android:gravity ="center_horizontal"
>
ImageButton >
LinearLayout >
|
3-2-5. Gestion du Scroll
|
//Tout d'abord, il faut supprimer tous les éléments du layout principal.
//Ce layout est déjà chargé par ailleurs.
layoutOfDynamicContent .removeAllViewsInLayout();
//Ensuite il faut définir et instancier la ScrollView. //le this correspond à l'Activité contenant ces lignes.
ScrollView scvMain = new ScrollView( this );
//On définit la couleur de fond du scroll.
scvMain .setBackgroundColor(0xFFCFDBEC);
//Et on rajoute la ScrollView au layout principal en lui demandant de remplir tout l'espace disponible.
layoutOfDynamicContent .addView( scvMain , new LinearLayout.LayoutParams(LinearLayout.LayoutParams. FILL _CONTENT , LinearLayout.LayoutParams. FILL _CONTENT ) );
//Ensuite on définit le layout qui contiendra les composants ajoutés dynamiquement. LinearLayout lilContent = new LinearLayout( this );
//code de construction dynamique de l'IHM.
//Ajout du layout à la ScrollView en lui demandant de remplir tout l'espace disponible. scvMain .addView( lilContent , new LinearLayout.LayoutParams(LinearLayout.LayoutParams. FILL _CONTENT , LinearLayout.LayoutParams. FILL _CONTENT ) );
|
3-2-6. Gestion des composants usuels
- déclarer et instancier le composant ;
- lui affecter un texte, une couleur de fond et une couleur de texte ;
- définir sa police de caractères et son type face (Bold, Italic, Normal) ;
- définir le texte à afficher par défaut quand le composant n'a pas de texte à afficher ;
- positionner la sauvegarde automatique de l'état du composant associé au cycle de vie de l'activité ;
- gérer son scrolling ;
- gérer sa visibilité ;
- et enfin, l'ajouter au layout qui est censé le contenir.
|
//Tout d'abord, déclarez et instanciez le composant en lui passant son Contexte.
//Ici le contexte n'est autre que l'activité dans lequel l'IHM est construite, d'où le this.
TextView txvTitle = new TextView( this );
//Affectation du texte à afficher par le composant. txvTitle .setText( "titre : " + post .getString( "titre" ));
//Affectation de sa couleur de fond.
txvTitle .setBackgroundColor(0xFF627AAD);
//Affectation de sa couleur de text.
txvTitle .setTextColor(0xFFFFFFFF);
//Définition du typeFace du composant (Italic, Bold, Normal,Bold_Italic), un autre type de typeFace étant la police : MonoSpace, Sans_Serif, Serif.
txvTitle .setTypeface(Typeface. defaultFromStyle (Typeface. BOLD ));
//Le texte à afficher quand il n'y a aucun texte à afficher par le composant (i.e. quand le composant n'a rien à afficher).
txvTitle .setHint( "C'est quoi un HintText" );
//La couleur du hint-texte.
txvTitle .setHintTextColor(0xFF555555);
//Pour permettre de sauver en mémoire l'état du composant quand l'activité sera détruite pour être restauré plus tard. txvTitle .setFreezesText( true );
//Ajout d'une scroll bar au composant. txvTitle .setHorizontallyScrolling( true );
//Mise en place d'une ligne de transparence horizontale (à droite et à gauche) lors du scroll du composant ou setVerticalFadingEdgeEnabled pour mettre cette ligne verticale (en haut et en bas), ou les deux. Si le composant n'a pas de scrollBar, cela ne fera rien.
txvTitle .setHorizontalFadingEdgeEnabled( true );
//Définition de la hauteur/largeur de cette ligne de transparence.
txvTitle .setLines(2);
//Gérez la visibilité du composant, il peut être Visible, Invisible (caché mais l'espace pour le composant reste réservé) ou Gone (caché et l'espace du composant est libéré et utilisé par les autres composants). txvTitle .setVisibility(View. VISIBLE );
//Et ainsi de suite, explorez l'API.
//Et ajout du composant au layout qui le contient. lilPost .addView( txvTitle , new LinearLayout.LayoutParams(LinearLayout.LayoutParams. FILL _CONTENT , LinearLayout.LayoutParams. FILL _CONTENT ) );
|
3-2-7. Gestion des composants images
- l'image est une ressource de votre application (dans un dossier res\drawable-**) ;
- l'image est une ressource du web (dont l'URL est connue, de type http://adresseWeb) ;
|
//Définition et instanciation du composant Image.
ImageView webPicture = new ImageView( this );
//Le drawable à afficher.
Drawable monDrawable = //Le Drawable à affecter ;
//Affectation du composant à l'image.
webPicture .setImageDrawable( //Le Drawable à affecter );
//Définition de la couleur de fond du composant (facultatif).
webPicture .setBackgroundColor(0xFFFFFFFF);
|
3-2-7-1. Cas d'une image contenue dans les ressources de l'application
|
int pictureId =getResources().getIdentifier( message .getString( "fromPicture" ), "drawable" , "com.android2ee.tuto.gui" );
picture .setBackgroundDrawable(getResources().getDrawable( pictureId ));
|
3-2-7-1-1. La méthode getIdentifier
- R.string.maChaine a pour type string ;
- R.layout.monLayout a pour type layout ;
- R.drawable.monImage a pour type drawable ;
- R.id.monComposant a pour type id.
|
/* AUTO-GENERATED FILE. DO NOT MODIFY.
*
* This class was automatically generated by the
* aapt tool from the resource data it found. It
* should not be modified by hand.
*/
package com.android2ee.tuto.gui; public final class R { public static final class attr {
}
public static final class drawable {
public static final int icon =0x7f020000;
public static final int icon_sti1 =0x7f020001;
public static final int icon_sti2 =0x7f020002;
public static final int icon_sti2b =0x7f020003;
public static final int icon_sti3 =0x7f020004;
}
public static final class id {
public static final int btnReload =0x7f050002;
public static final int layoutOfDynamicContent =0x7f050003;
public static final int mainlayout =0x7f050000;
public static final int txvHello =0x7f050001;
}
public static final class layout {
public static final int main =0x7f030000;
}
public static final class string {
public static final int app_name =0x7f040001;
public static final int hello =0x7f040000;
public static final int reload =0x7f040002;
}
}
|
- le paramètre defPackage est le package du fichier ;
- le paramètre defType est le nom de classe contenant votre identifiant (la public static final class ) ;
- le paramètre name est le nom de l'identifiant contenu dans cette classe.
3-2-7-2. Cas d'une image provenant du web
|
/**
* Cette méthode renvoie le Drawable associé à une URL d'image
* @param urlPath l' URL de l'image
* @return L'objet Drawable téléchargé à partir de l' URL passée en paramètre
*/
private Drawable getPicture (String urlPath ) {
// Le drawable à renvoyer
Drawable drawable = null ;
try {
// Récupération de l'URL à partir de sa représentation sous forme de String.
URL URL = new URL ( urlPath );
//Ouverture de l'inputStream associé à cette URL pour sa lecture.
InputStream is = (InputStream) URL .getContent();
// Construction du Drawable à partir de ce flux entrant.
drawable = Drawable. createFromStream ( is , "src" );
} catch (IOException e ) {
Log. e ( tag , e .toString());
//Si une exception se produit faire quelque chose d'intelligent.
}
// Renvoyer le résultat.
return drawable ;
}
|
|
// Instanciation du composant image.
ImageView webPicture = new ImageView( this );
//Récupération du Drawable par appel à la méthode getPicture et affectation au composant.
|
3-2-8. Mise en place de données factices pour les tests
| Nom du champ | Type de la donnée |
| Titre | String |
| Description | String |
| Messages | List |
| FromWebPicture | Drawable |
Où l'objet Message est le suivant :
| Titre | String |
| Message | String |
| From | String |
| FromPicture | Drawable |
Le Format JSON est celui choisi pour cet exemple.
|
private JSONObject generateOneData () {
try {
//Instanciation et déclaration de l'objet JSON.
JSONObject jsonPost = new JSONObject();
//Récupération d'un entier de référence (le choix du sujet du post).
int selectedInt = getRandomInt(6);
//Instanciation de ce sujet.
String subject = titres [ selectedInt ];
//Ajout du champ name avec la valeur post à l'objet JSON.
jsonPost .put( "name" , "post" );
//Ajout du champ titre avec la valeur subject à l'objet JSON.
jsonPost .put( "titre" , subject );
//Ajout du champ name avec la valeur post à l'objet JSON.
jsonPost .put( "description" , descriptions [ selectedInt ]);
//Ajout du champ FromWebPicture avec la valeur le nom de l'URL de l'image à l'objet JSON.
jsonPost .put( "fromWebPicture" , webDrawables [ selectedInt ]);
//Déclaration et instanciation d'un tableau JSON.
JSONArray jsonMessagesList = new JSONArray();
//Déclaration de l'objet JSON qui sera ajouté au tableau.
JSONObject jsonMessage ;
//entier permettant d'associer la même image au même champ « from » .
int fromNum ;
//Création en boucle des objets JSON à insérer dans le tableau.
for ( int i = 0; i < getRandomInt(9); i ++) {
//Instanciation de l'objet JSON, ajout de valeurs et ajout à la liste :
jsonMessage = new JSONObject();
jsonMessage .put( "name" , "message" );
jsonMessage .put( "titre" , titresMessages [getRandomInt(6)] + " " + subject );
jsonMessage .put( "message" , messages [getRandomInt(7)] + " " + subject );
fromNum =getRandomInt(4);
jsonMessage .put( "from" , from [ fromNum ]);
jsonMessage .put( "fromPicture" , drawables [ fromNum ]);
jsonMessagesList .put( jsonMessage );
}
//Ajout du tableau à l'objet JSON initial.
jsonPost .put( "messages" , jsonMessagesList );
//Et retour.
return jsonPost ;
} catch (JSONException e ) {
//Faire quelque chose d'intelligent ici :
return null ;
}
} |
|
/**
* 6 items Titres. Items utilisés lors de la génération des données.
*/
String[] titres = { "" };
/**
* 6 items Descriptions. Items utilisés lors de la génération des données.
*/
String[] descriptions = { "" };
/**
* 6 items titre du message. title Items utilisés lors de la génération des données.
*/
String[] titresMessages = { "" };
/**
* 7 items corps du message. Items utilisés lors de la génération des données.
*/
String[] messages = { "" };
/**
* 4 items auteur du message. Items utilisés lors de la génération des données.
*/
String[] from = { "" };
/**
* 4 items image de l'auteur. Items utilisés lors de la génération des données.
*/
String[] drawables = { "" };
/**
* 5 items image du sujet en provenance du web. Items utilisés lors de la génération des données.
*/
String[] webDrawables = { "" };
|
4. Récupération du tutoriel
5. Contact

6. Android2ee vous présente l'Ebook de programmation Android
7. Remerciements
Copyright ©2011 Mathias Seguy. Aucune reproduction, même 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 intérêts. Cette page est déposée à la SACD.











