1. Les listes

Sous Android, une liste représente un ensemble d'éléments s'affichant les uns à la suite des autres.

Chaque élément d'une liste peut posséder de une à trois lignes maximum et chaque ligne d'une liste peut être personnalisée avec différents composants (TextView, Button, ImageView…).

Vous disposez de deux modes pour créer une liste. L'activité intégrant la liste peut:
  • Soit hériter de la classe ListActivity.
  • Soit hériter de la classe Activity.

Pour insérer des données dans une liste, on utilise un adapter(adaptateur). Il permet de lier des données à une vue qui étend de la classe AdapterView, ainsi il est facile d'accéder aux données st ockées (lire, ajouter, supprimer, modifier…) dans une vue. Android propose deux types d'adapters:

ArrayAdapter: permet de remplir une liste à partir d'un tableau ou d'une collection.

SimpleCursorAdapter: permet de remplir une liste à partir d'une base de données.

Vous pouvez aussi créer votre propre adapter en héritant simplement de la classe BaseAdapter ou d'un adapter déjà existant.

1-1. Création d'une liste

1-1-1. ListActivity

La première méthode consiste à créer une liste héritant de la classe ListActivity.

Pour commencer, créez un fichier XML représentant une vue contenant uniquement une liste (dossier layout).

 
Sélectionnez
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:orientation="vertical" >
  <ListView
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:id="@android:id/list" />
</LinearLayout>

Pour pouvoir manipuler une ListView grâce à une ListActivity, votre liste doit absolument avoir pour identifiant @android:id/list.

Maintenant, déclarez une activité qui hérite de la classe ListActivity.

 
Sélectionnez
 public class ListActivityExampleActivity extends ListActivity {
    
  @Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
  }
}

Pour l'instant la liste est vide et ne co ntient aucune donnée. Nous allons utiliser un tableau de chaînes de caractères comme source de données.

 
Sélectionnez
private String[] androidVersion = {"Cupcake", "Donut", "Eclair",
"Froyo", "Gingerbread", "Honeycomb", "Ice Cream Sandwich" 
"Jelly Bean"};

Créez un ArrayAdapter afin d'injecter dans la liste les données provenant du tableau déclaré précédemment.

 
Sélectionnez
ArrayAdapter adapter = new ArrayAdapter(this, 
        android.R.layout.simple_list_item_1,
androidVersion);
La méthode permettant de construire un ArrayAdapter nécessite trois paramètres:
  • Le premier paramètre représente le contexte de l'activité courante.
  • Le deuxième paramètre représente le layout qui sera appliqué à chaque ligne de la liste. Vous pouvez soit créer un layout personnalisé, soit utiliser ceux fournis par Android.
  • Le troisième paramètre représente le tableau de données à insérer dans la liste.

La dernière étape consiste à lier l'adapter contenant les données à injecter à la liste et cela à l'aide de la méthode setListAdapter:

 
Sélectionnez
SetListAdapter(adapter);

Maintenant, vous pouvez tester cet exemple et vous devriez obtenir le résultat suivant:

1-1-2. ListView

La seconde manière de créer une liste est d'utiliser une simple activité.

Pour cela, il faut créer le fichier XML représentant la liste.

 
Sélectionnez
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:orientation="vertical" >
  <ListView
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:id="@+id/myList" />
</LinearLayout>

Remarque:

Cette méthode offre la possibilité de spécifier l'identifiant de votre choix.

Modifiez l'activité afin de récupérer l'instance de la liste (à l'aide de la méthode findViewById).

 
Sélectionnez
ListView myList = (ListView) findViewById(R.id.myList);

Comme précédemment, l'exemple utilise un tableau de chaînes de caractères ainsi qu'un ArrayAdapter.

Pour finir, il faut associer l'adapter à la liste.

 
Sélectionnez
myList.setAdapter(adapter);

Remarque:

L'utilisation d'une ListActivity est conseillée si votre vue contient uniquement une liste.

1-1-3. Adapter et liste personnalisée

Vous pouvez aussi créer des adapters personnalisés afin de mieux gérer l'affi-chage et les données d'une liste.

Voici un exemple permettant d'afficher une liste contenant le nom et le numéro des différentes versions d'Android et cela, à l'aide d'un adapter personnalisé.

Pour commencer, créez une classe AndroidVersion représentant tout simplement une version d'Android.

 
Sélectionnez
public class AndroidVersion {
   private String versionName;
   private String versionNumber;
   public String getVersionName() {
   return versionName;
  }
   public void setVersionName(String versionName) {
   this.versionName = versionName;
  }
   public String getVersionNumber() {
   return versionNumber;
  }
   public void setVersionNumber(String versionNumber) {
   this.versionNumber = versionNumber;
  }
  
}

L'exemple utilise un adapter personnalisé héritant de la classe ArrayAdapter(car il utilise un tableau pour in jecter des données dans la liste).

Pour cela, créez d'abord un fichier qui représentera la liste.

 
Sélectionnez
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:orientation="vertical" >
  <ListView
    android:id="@+id/myList"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" />
</LinearLayout>

Afin de personnaliser la liste et la rendre plus riche et plus agréable, il faut créer un layout personnalisé qui servira à spécifier l'interface correspondant à chaque ligne de la liste.

 
Sélectionnez
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="?android:attr/listPreferredItemHeight"
  android:padding="6dip" >
  <ImageView
    android:id="@+id/icon"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginRight="6dp"
    android:src="@drawable/list_icon" />
  <LinearLayout
    android:layout_width="wrap_content"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
    <TextView
      android:id="@+id/title"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:gravity="center_vertical" 
      />
    <TextView
      android:id="@+id/description"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content" 
      />
    
  </LinearLayout>
  </LinearLayout>
					

Chaque ligne de la liste est donc composée des éléments suivants:

–Un LinearLayout horizontal.

Une image:
  • L'image se situe dans le dossier drawable.
  • L'image possède un espacement extérieur ( margin) droit de 6dp .

– Un second LinearLayout (vertical) utilisé pour afficher les deux zones de textes (titre et description).

– Un premier texte qui indiqu e le titre de la ligne.

– Un second texte qui indique la description de la ligne.

Maintenant, créez une classe représentant l'adapter personnalisé. Il possédera les spécificités suivantes:

– Il hérite de la classe ArrayAdapter car le remplissage des données sera ef-fectué à l'aide d'un tableau.

– Chaque élément de la liste représente une version d'Android.

Il possède les deux méthodes suivantes:
  • Un constructeur.
  • Une méthode getView: chaque appel à cette méthode permet de récu-pérer une ligne (donnée et vue) de la liste se trouvant à une position donnée.
 
Sélectionnez
public class AndroidAdapter extends ArrayAdapter<AndroidVersion>
{
   ArrayList<AndroidVersion> androidVer;
  int viewRes;
 
   public AndroidAdapter(Context context, int
textViewResourceId,
     ArrayList<AndroidVersion> versions) {
   super(context, textViewResourceId, versions);
   this.androidVer = versions;
   this.context = context;
   this.viewRes = textViewResourceId;
  }
  @Override
   public View getView(int position, View convertView, ViewGroup
parent) {
   View v = convertView;
   if (v == null) {
         LayoutInflater vi = (LayoutInflater)
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         v = vi.inflate(viewRes, parent, false);
   } 
   AndroidVersion o = androidVer.get(position);
   if (o != null) {
         TextView tt = (TextView) v.findViewById(R.id.title);
     TextView bt = (TextView)
     v.findViewById(R.id.description);
         if (tt != null) {
         tt.setText("Nom de la version : " +
o.getVersionName());
     }
         if (bt != null) {
            bt.setText("Numéro de la version : " +
o.getVersionNumber());
     }
   }
   return v;
  }
}
Le constructeur sert à stocker les trois arguments nécessaires pour l'implémentation de l'adapter:
  • Le contexte de la vue.
  • Le layout correspondant à la vue personnalisée, appliqué à chaque ligne de la liste.
  • Le tableau représentant les données à insérer dans la liste.
La méthode getView(int position, View convertView, ViewGroup parent):
  • Cette méthode permet de récupérer la vue à appliquer à une ligne donnée (argument position).
  • La vue représentant la liste est passée en argument à la méthode (argument convertView).
  • La vue parente est passée en argument (argument parent).
  • La vue personnalisée doit être chargée à l'aide de la méthode inflate. Une fois chargée, elle sera passée en paramètre à la méthode getView(paramètre convertView) lors des prochains appels, ce qui réduit le nombre d'appels à la méthode inflate (appel assez coûteux).
  • Puis il faut récupérer le texte correspondant à la ligne qu'on souhaite afficher.
  • Enfin, il faut récupérer les deux TextView(titre et description d'une ligne) afin de les remplir avec les données récupérées dans l'étape précédente.

Vous pouvez aller plus loin dans l'optimisation d'une liste et cela à l'aide du système de holder.

Pour finir, créez l'activité qui permet d'initialiser la vue, l'adapter personnalisé et les données.

 
Sélectionnez

public class CustomAdapterExampleActivity extends Activity {
  @Override
   public void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.main);
   ArrayList<AndroidVersion> androidList = new
ArrayList<AndroidVersion>();
     initList(androidList);
         AndroidAdapter adapter = new AndroidAdapter(this,
R.layout.list_layout, androidList);
     final ListView list = (ListView)
findViewById(R.id.myList);
     list.setAdapter(adapter);
  }
   private void initList(ArrayList<AndroidVersion> androidList)
{
   AndroidVersion version = new AndroidVersion();
   version.setVersionName("Cupcake");
   version.setVersionNumber("1.5");
   androidList.add(version);
   AndroidVersion versionDonut = new AndroidVersion();
   versionDonut.setVersionName("Donut");
   versionDonut.setVersionNumber("1.6");
   androidList.add(versionDonut);
      AndroidVersion versionEclair = new AndroidVersion();
   versionEclair.setVersionName("Eclair");
   versionEclair.setVersionNumber("2.0.x");
   androidList.add(versionEclair);
   
   AndroidVersion versionFroyo = new AndroidVersion();
   versionFroyo.setVersionName("Froyo");
   versionFroyo.setVersionNumber("2.2.x");
   androidList.add(versionFroyo);
     .........
  }
}
Cette activité permet:
  • D'initialiser la liste des données (méthode initList).
  • D'initialiser l'adapter en lui passant les arguments nécessaires à son bon fonctionnement (contexte, vue et données).
  • Récupérer la liste et la lier à l'adapter.

Ce qui donnera le résultat suivant:

Gestion du clic sur une liste

Pour gérer le clic sur les différents éléments d'une liste, utilisez la méthode setOnItemClickListener sur l'instance de la liste cible.

 
Sélectionnez

list.setOnItemClickListener(new OnItemClickListener() {
  @Override
   public void onItemClick(AdapterView<?> adapter, View v, int
position, long id) {
   AndroidVersion selectedItem = (AndroidVersion)
adapter.getItemAtPosition(position);
      Log.v("CustomAdapterExemple", "Element selectionne : "
+ selectedItem.getVersionName());
  }
});
La méthode onItemClick possède quatre arguments:
  • L'adapter sur lequel le clic est survenu.
  • La vue sur laquelle le clic est survenu.
  • La position du clic dans l'adapter.
  • L'identifiant de la position du clic dans la vue.

Ensuite, récupérez l'instance de la classe AndroidVersion qui correspond à la zone sélectionnée par l'utilisateur afin de l'afficher dans un Log.

2. Fragment

Un fragment (cf. chapitre Principes de programmation - Composantes Android) est un composant qui doit être attaché à une activité pour être utilisé. Son cycle de vie ressemble à celui de l'activité parente mais possède quelques spécificités.

2-1. Cycle de vie d'un fragment

La première étape du cycle de vie d'un fragment correspond à l'instant où le fragment est attaché à l'activité parente (onAttach). Puis le fragment est initialisé lors de l'appel à la méthode onCreate, suivi de la créati on et du chargement de l'interface du fragment (méthode onCreateView).

Une fois que l'activité parente et le fragment sont créés, l'appel à la méthode onActivityCreated signifie la fin du cycle de création de l'interface.

La méthode onStart coïncide avec le passage du fragment au premier plan, suivi de l'appel à la méthode onResume (même fonctionnement que pour une activité - cf. chapitre Principes de programmation - Cycle de vie d'une activité).

Lorsqu'un fragment devient inactif, l'appel à la méthode onPause permet d'exécuter les actions adéquates (désactivation des mises à jour de l'interface, listener…). Cet appel est suivi par la méthode onStop (le fragment n'est plus au premier plan).

Si un fragment est détruit, les méthodes suivantes seront respectivement appelées:
  • onDestroyView: destruction de la vue.
  • onDestroy: destruction du fragment.
  • onDetach: le fragment est séparé de l'activité parente.

2-2. Exemple

Dans l'exemple ci-dessous, nous allons créer une vue composée de deux parties:

L'application en mode portrait: elle sera composée de deux activités. La première représentera la liste des versions d'Android et la seconde représentera la vue de détails affichée lorsque l'utilisateur clique sur un élément de la liste.

L'application en mode paysage: elle sera composée d'une seule activité mais de deux fragments. Au moment où l'utilisateur clique sur la liste qui se trouve sur le premier fragment, le second se met automatiquement à jour avec les détails.

Pour commencer, créez dans le dossier layout un fichier XML représentant la vue en mode paysage (vue composée de de ux fragments).

 
Sélectionnez
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:orientation="horizontal" >
  <fragment
    android:id="@+id/listFragment"
    android:layout_width="150dip"
    android:layout_height="match_parent"
    class="com.eni.android.fragment.ListFragment" >
</fragment>
  <fragment
    android:id="@+id/detailFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    class="com.eni.android.fragment.DetailFragment" >
  </fragment>
</LinearLayout>
Ce fichier se compose de deux fragments :
  • Fragment 1: représente une liste des versio ns d'Android. Il est déclaré dans le fichier ListFragment (cf. attribut class).
  • Fragment 2: représente la vue détaillée d' une version d'Android. Il est déclaré dans le fichier DetailFragment.

Maintenant, implémentez le premier fragment (liste des versions d'Android) héritant de la classe ListFragment.

 
Sélectionnez
public class ListFragment extends android.app.ListFragment {
private String[] values = {"Cupcake", "Donut", "Eclair", "Froyo",
   "Gingerbread", "Honeycomb", "Ice Cream Sandwich", "Jelly Bean"};
  @Override
   public void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
  }
  @Override
   public void onActivityCreated(Bundle savedInstanceState) {
   super.onActivityCreated(savedInstanceState);
   ArrayAdapter<String> adapter = new 
ArrayAdapter<String>(getActivity(),
        android.R.layout.simple_list_item_1, values);
   setListAdapter(adapter);
  @Override
   public void onListItemClick(ListView l, View v, int position, 
long id) {
   String item = (String) getListAdapter().getItem(position);
   DetailFragment fragment = (DetailFragment)
getFragmentManager().findFragmentById(R.id.detailFragment);
      if (fragment != null && fragment.isInLayout()) {
     fragment.setText(item);
   } else {
         Intent intent = new 
Intent(getActivity().getApplicationContext(),
        DetailActivity.class);
        intent.putExtra("value", item);
     startActivity(intent);
   }
  }
        
La méthode OnActivityCreated est appelée à la création d'un fragment.
  • Dans cette méthode, l'adapter est initialisé à l'aide du tableau values.
  • Puis la liste est liée à l'adapter.
La méthode onListItemClick est surchargée pour gérer le clic sur un élément de la liste:
  • L'élément cliqué est récupéré à l'aide de l'adapter.
  • Le fragment servant à afficher les détails est initialisé.
  • Si aucun problème n'est rencontré lors de l'initialisation, cela signifie que l'application est en mode paysage et donc que l'utilisation du fragment des détails est possible, sinon l'application est en mode portrait.
  • Si l'initialisation fonctionne correctement, cela permet de définir le texte à afficher dans le fragment des détails.
  • Sinon, il faut exécuter l'activité des détails et non le fragment des détails.

Maintenant, il faut implémenter le fragment servant à afficher les détails:

 
Sélectionnez
public class DetailFragment extends Fragment {
  @Override
   public void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
  }
  @Override
   public void onActivityCreated(Bundle savedInstanceState) {
   super.onActivityCreated(savedInstanceState);
  }
  @Override
   public View onCreateView(LayoutInflater inflater, ViewGroup
container,
     Bundle savedInstanceState) {
   View view = inflater.inflate(R.layout.details,
container, false);
   return view;
  }
   public void setText(String item) {
   TextView view = (TextView)
getView().findViewById(R.id.detailsText);
   view.setText(item);
  }
}

Une fois ces étapes effectuées, le mode paysage est donc correctement implémenté.

L'étape suivante consiste à implémenter les interfaces et les traitements pour le mode portrait. Pour cela, il faut créer un dossier layout-port qui contiendra une seconde version du fichier main.xml.

 
Sélectionnez
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:orientation="horizontal" >
  <fragment
    android:id="@+id/listFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    class="com.eni.android.fragment.ListFragment" />
  
</LinearLayout>

Dans cette version, le fichier est composé d'un seul fragment (celui qui affiche la liste des versions d'Android). Les différences entre le fichier main.xml en mode portrait et paysage permettent d'identifier l'orientation à l'initialisation de la vue et donc d'adopter le bon comp ortement en fonction de ces deux cas.

Créez un fichier XML représentant la vue détails. Il contiendra le fragment permettant d'afficher les détails d'une version d'An droid en mode portrait.

 
Sélectionnez
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical" >
  <fragment
    android:id="@+id/detailFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    class="com.eni.android.fragment.DetailFragment" />
</LinearLayout>

Nous avons finalement simplement séparé les deux fragments qui se trouvaient dans le même fichier (mode paysage) en deux fichiers distincts (mode portrait).

Maintenant, il faut créer l'activité qui permet de gérer la vue de détails.

 
Sélectionnez
public class DetailActivity extends Activity {
  @Override
   protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.details_activity_layout);
   Bundle extras = getIntent().getExtras();
      if (extras != null) {
         String s = extras.getString("value");
     TextView view = (TextView)
findViewById(R.id.detailsText);
     view.setText(s);
   }
  }
}

Cette activité charge le nouveau layout et affiche la chaîne de caractères passée en argument (extras).

Pour finir, voici l'activité principale de l'exemple:

 
Sélectionnez
public class FragmentExempleActivity extends Activity {
  @Override
   public void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.main);
  }
}

Et le fichier manifeste contenant les différentes déclarations:

 
Sélectionnez
<application
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name" >
    <activity
      android:name=".FragmentExempleActivity"
      android:label="@string/app_name" >
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
         <category
android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>
    <activity android:name=".DetailActivity"></activity>
  </application>

Vous pouvez maintenant tester l'exemple tout d'abord en mode portrait puis en mode paysage. Ce qui donnera les résultats suivants:

Mode portrait - Liste des versions d'Android
Mode portrait - Détail d'une version d'Android
Mode paysage

3. Passage en mode plein écran

Certaines applications nécessitent le passage en mode plein écran (lecture de vidéo par exemple). Un passage en mode plein écran peut signifier que l'appli-cation cache la barre de notification du téléphone et/ou la barre de navigation (sauf dans le cas d'une tablette).

Le cas d'une tablette est assez différent car les barres de notification et de navigation se trouvent toutes les deux sur la barre de système. Ce qui ne permet pas de les cacher mais juste de les obscurcir afin de les rendre moins visibles.

Voici la méthode permettant de cacher la barre de notification sur un smartphone et de les obscurcir sur une tablette:

 
Sélectionnez
onSystemUiVisibilityChange(int visibility)

Cette méthode possède un argument pouvant prendre les valeurs suivantes:

SYSTEM_UI_FLAG_LOW_PROFILE: permet d'obscurcir la barre de navigation.

SYSTEM_UI_FLAG_HIDE_NAVIGATION: permet de cacher la barre de navigation.

Remarque:

Vous pouvez aussi obscurcir la barre de navigation sur un smartphone.

Néanmoins, Android 4 introduit une limitation (due à l'absence de bouton physique): à la moindre interaction de l'utilisateur avec l'activité en cours d'exécution, les barres de navigation apparaissent à nouveau.

Si vous souhaitez plutôt cacher la barre de notification d'un smartphone (lecture vidéo ou jeux vidéo par exemple), il suffit d'utiliser la méthode suivante à l'initialisation d'une activité :

 
Sélectionnez
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

Remarque:

Ne cachez la barre de notification que si nécessaire car elle est importante pour l'interaction de l'utilisateur avec l'appareil (accès aux évènements importants arrivant sur l'appareil).

4. Interfaces dynamiques

Créer des interfaces plus riches peut passer par la création d'interfaces dynamiques. Une interface dynamique est une interface créée en Java, directement dans le fichier source d'une activité.

Remarque:

Une interface dynamique peut être combinée avec une interface statistique (fichier XML).

La création dynamique d'interface est très utile dans le cas où vous voulez rajouter des composants à la volée dans une interface.

Pour illustrer cette fonctionnalité, l'exemple suivant sert à créer une interface composée d'un bouton qui servira à rajouter des zones d'édition (EditText) dynamiquement dans l'interface.

Cette vue contient tout simplement un LinearLayout et un bouton possédant un identifiant.

 
Sélectionnez
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:orientation="vertical" 
  android:id="@+id/linearlayout">
  <Button
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="@string/addEditText" 
    android:id="@+id/addBtn"/>
</LinearLayout>

Lors du clic sur le bouton, des zones d'édition seront rajoutées dynamiquement à la vue.

 
Sélectionnez
public class DynamicViewActivity extends Activity {
  @Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    final LinearLayout linearLayout = (LinearLayout) 
findViewById(R.id.linearlayout);
    Button btn = (Button) findViewById(R.id.addBtn);
    btn.setOnClickListener(new OnClickListener() {
       @Override
       public void onClick(View v) {
         EditText edit = new
EditText(DynamicViewActivity.this);
         edit.setHint(R.string.newEditText);
         LayoutParams layoutParams = new
LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT);
      edit.setLayoutParams(layoutParams);
      linearLayout.addView(edit);
     }
   });
  }
}
Pour créer dynamiquement des EditText :
  • Il faut créer une zone d'édition à l'aide de son constructeur en lui passant le contexte nécessaire à son initialisation.
  • Cette zone d'édition a un texte par défaut ( setHint).
  • Les layoutParams servent à spécifier des valeurs et propriétés à un EditText(notamment sur la largeur et la hauteur).
  • Puis pour finir, il faut ajouter la zone d'édition créée dans le LinearLayout récupéré précédemment (grâce à son identifiant).

Voici le résultat obtenu:

5. Création d'onglets

5-1. Principe

Les onglets permettent de basculer plus facilement entre plusieurs vues et d'améliorer ainsi l'expérience utilisateur d'une application.

Il existe trois types d'onglets:

Les onglets scrollables (exemple de Google Play):

– Ils peuvent contenir un grand nombre d'onglets.

– La navigation entre les onglets s'effectue en glissant un doigt de gauche à droite ou inversement.

Les onglets fixes (exemple de l'application Contacts):

– Les onglets sont affichés les uns à la suite des autres.

– Ils peuvent contenir jusqu'à trois onglets maximum.

Les onglets empilés (exemple de l'application Youtube):

– Ils permettent de séparer ou fusionner des onglets avec une ActionBar (cf. chapitre Création d'interfaces simples - Barre d'actions (ActionBar)).

5-2. Implémentation d'onglets scrollables

Ce composant est utilisable à l'aide de la classe ViewPager qui est disponible dans le Compatibility Package. Ce dernier est téléchargeable dans la partie extras du SDK Android (cf. chapitre Environnement de développement -SDK Android).

Une fois téléchargé, vous devez intégrer la bibliothèque téléchargée dans le projet grâce au fichier jar se trouvant dans le dossier extras de votre SDK Android.

La première étape consiste à intégrer le ViewPager dans une interface XML.

 
Sélectionnez
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:orientation="vertical"
  android:background="#fff" >
  <android.support.v4.view.ViewPager
    android:layout_width="match_parent"
    android:layout_height="match_parent" 
    android:id="@+id/viewPager"/>
</LinearLayout>

Vous pouvez remarquer que le ViewPager n'est pas un élément natif du SDK mais provient bien du Compatibility Package.

La prochaine étape consiste à créer un adapter personnalisé pour la classeViewPager. Cet adapter doit hériter de la classe PagerAdapter et implémenter les méthodes suivantes:

getCount: retourne le nombre de vues disponibles dans l'interface.

instantiateItem: crée la page située à une position donnée.

destroyItem: supprime une page située à une position donnée.

isViewFromObject: détermine si la vue est associée à un objet.

finishUpdate: appelle quand toutes les mises à jour sur la page actuelle sont effectuées.

restoreState: restaure l'état d'une page.

saveState: sauvegarde l'état d'une page.

startUpdate: appelle pour mettre à jour la page actuelle.

 
Sélectionnez
private class ViewPagerAdapter extends PagerAdapter {
  @Override
   public int getCount() {
   return NUMBER_OF_PAGES;
  }
  @Override
   public Object instantiateItem(View collection, int position) {
   TextView tv = new TextView(ViewPagerExempleActivity.this);
   tv.setText("Page numero : " + position);
  tv.setTextColor(Color.BLACK);
  tv.setTextSize(30);
   ((ViewPager) collection).addView(tv, 0);
   return tv;
}
  @Override
     public void destroyItem(View collection, int position,
Object view) {
      ((ViewPager) collection).removeView((TextView) view);
     }
     
  @Override
    public boolean isViewFromObject(View view, Object object) {
      return view==((TextView)object);
  }
  @Override
    public void finishUpdate(View arg0) {}
     
  @Override
    public void restoreState(Parcelable arg0, ClassLoader arg1) {}
  @Override
  public Parcelable saveState() {
      return null;
  }
  @Override
    public void startUpdate(View arg0) {}
}
     

Voici quelques explications sur l'adapter créé:

–La méthode getCount doit retourner le nombre de pages disponibles dans l'adapter.

instantiateItem: permet d'instancier la vue actuelle. Dans l'exemple, une zone de texte dans laquelle il faut afficher le numéro de la page est créée. Puis cette zone de texte est ajoutée au ViewPager.

destroyItem: permet de détruire l'élément actuel.

isViewFromObject: compare la vue actuelle avec l'objet passé en argument.

Ce qui donnera:

6. Les popups

6-1. Les toasts

Les toasts servent à indiquer un message court, une indication ne nécessitant pas d'interaction utilisateur.

Créer un toast peut se faire depuis une activité, un service ou toute autre classe possédant un contexte.

 
Sélectionnez
 Toast.makeText(ToastExampleActivity.this, R.string.toast,Toast.LENGTH_SHORT).show();

Pour créer un toast, utilisez la méthode makeText qui prend pour arguments:

–Le contexte.

– La chaîne à afficher.

– La durée de l'affichage du toast.

– Vous disposez de deux valeurs prédéfinies : Toast.LENGTH_SHORT et Toast.LENGTH_LONG.

La méthodeshow sert à afficher le toast.

Ce qui donnera:

Remarque:

N'oubliez pas d'appeler la méthode show pour afficher le Toast.

6-2. AlertDialog

Une AlertDialog est une boîte de dialogue permettant d'afficher un message et d'effectuer une interaction avec l'utilisateur.

Elle se compose de trois parties:

–Un titre (optionnel): représente le titre de la boîte de dialogue.

–Un contenu: représente le contenu d'une boîte de dialogue. Elle peut contenir des zones de texte, des sliders, des cases à cocher, des boutons radio, etc.

–Un bouton ou plusieurs boutons d'actions: permet à l'utilisateur de choisir l'action à effectuer.

Voici un exemple pour une boîte de dialogue demandant à l'utilisateur de confirmer la suppression d'un message.

 
Sélectionnez
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(R.string.alert_dialog_msg).setCancelable(false
).setPositiveButton("Yes", new OnClickListener() {
  @Override
   public void onClick(DialogInterface dialog, int which) {
   dialog.cancel();
  }
}).setNegativeButton("Cancel", new OnClickListener() {
  @Override
   public void onClick(DialogInterface dialog, int which) {
   dialog.cancel();
  }
});
builder.create().show();

Dans ce code:

– Vous utilisez un AlertDialog.Builder pour créer une boîte de dialogue.

– Vous spécifiez le message ainsi que les boutons à afficher. Vous pouvez aussi avoir un seul bouton à l'aide de la méthode setNeutralButton.

– Puis vous appelez la méthode create pour créer la boîte de dialogue.

– Pour finir, vous utilisez la méthode show pour afficher la boîte de dialogue.

Ce qui donnera:

6-3. ProgressDialog

Les barres de progression servent à informer un utilisateur de l'avancement d'une tâche.

Il existe deux types de barres de progression :

Barre de progression bornée:si vous voulez, par exemple, connaître le pourcentage d'avancement d'une tâche (exemple de téléchargement d'une application sur Google Play).

Barre de progression non bornée: si la durée du traitement ne peut pas être calculée, vous pouvez utiliser ce type de barre de progression:

6-3-1. 1 Implémentation

Pour implémenter une barre de progression, il faut utiliser la classe Progress-Dialog.

Voici un exemple de création d'une barre de progression:

 
Sélectionnez
 ProgressDialog dialog = ProgressDialog.show(
ProgressDialogExampleActivity.this,
getResources().getString(R.string.dialog_title), getResources()
.getString(R.string.dialog_load), true);

La construction nécessite:

–Un contexte.

– Une chaîne de caractères servant de titre à la boîte de progression (optionnel).

– Une chaîne de caractères représentant le message affiché par la boîte de progression.

Ce qui donnera:

Une fois le traitement effectué, vous devez arrêter la barre de progression à l'aide de la méthode dismiss:

 
Sélectionnez
dialog.dismiss();
Pour créer une barre de progre ssion horizontale, il faut :
  • Créer une instance de la classe ProgressDialog.
  • Définir le style de la barre de progression (style horizontal)
  • Définir le message.
  • Afficher la barre de progression.
 
Sélectionnez
ProgressDialog progressDialog;
progressDialog = new
ProgressDialog(ProgressDialogExampleActivity.this);
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.setMessage("Loading...");
progressDialog.show();

Pour mettre à jour l'avancement de la tâche en cours, utilisez la méthode set-Progress:

 
Sélectionnez
progressDialog.setProgress(PROGRESS_VALUE);

6-4. Boîte de dialogue personnalisée

Vous pouvez créer des boîtes de dialogue personnalisées avec un layout spécifique. Pour cela, créez un fichier XML représentant le layout personnalisé.

 
Sélectionnez
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout_root"
       android:orientation="horizontal"
       android:layout_width="fill_parent"
       android:layout_height="fill_parent"
       android:padding="10dp"
       >
  <ImageView android:id="@+id/alert_img"
        android:layout_width="wrap_content"
        android:layout_height="fill_parent"
        android:layout_marginRight="10dp"
        />
  <TextView android:id="@+id/alert_msg"
       android:layout_width="wrap_content"
       android:layout_height="fill_parent"
       android:textColor="#FFF"
       android:gravity="center_vertical"
       />
</LinearLayout>
Puis dans l'activité, il faut :
  • Créer la boîte de dialogue.
  • Lier la boîte de dialogue au fichier XML représentant la vue personnalisée.
  • Spécifier un titre, une image et une description pour la boîte de dialogue.
 
Sélectionnez
Dialog dialog = new
Dialog(CustomAlertDialogExampleActivity.this);
dialog.setContentView(R.layout.custom_alert);
dialog.setTitle("Popup Personnalisée")
TextView text = (TextView) dialog.findViewById(R.id.alert_msg);
text.setText("Ma première Popup personnalisée !! "); 
ImageView image = (ImageView)dialog.findViewById(R.id.alert_img);
image.setImageResource(R.drawable.nyan);
    
dialog.show();

7. Préférences

Les préférences permettent de créer des écrans spécifiquement dédiés à la création et à la gestion des préférences d'un utilisateur dans une application ou de manière globale sur un appareil.

Depuis la version 3.0 d'Android, vous devez utiliser la classe PreferenceFragment pour créer les écrans de préférences d'une application.

Les préférences créées à l'aide de la classe PreferenceFragment seront automatiquement sauvegardées dans des SharedPreferences (cf. chapitre Persis-tance de données - SharedPreference).

Remarque:

Pour récupérer le SharedPreferences spécifique à la sauvegarde des préférences, appelez la méthode getDefaultSharedPreferences.

Pour créer un écran de préférences, vous disposez de plusieurs composants.

Chaque composant possède son contexte d'utilisation:
  • Case à cocher/Switcher: utilisez ce composant pour les options possédant seulement deux états (activé ou non).
  • Choix multiple: utilisez ce composant lorsqu'un utilisateur doit choisir une option parmi plusieurs possibles.
  • Slider: utilisez ce composant lorsqu'un utilisateur doit choisir une valeur dans une rangée de valeurs possibles.

Pour créer un écran représentant des préférences d'une application, commencez par créer un dossier nommé xml dans les ressources d'une application. En effet, le dossier xml est l'emplacement naturel des interfaces de préférences.

Créez un fichier représentant une interface de préférences:

 
Sélectionnez
<?xml version="1.0" encoding="utf-8"?><PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android" >
  <PreferenceCategory android:title="@string/notification" >
    <SwitchPreference
      android:key="checkbox_preference"
      android:title="@string/enable_notification" />
  </PreferenceCategory>
  <PreferenceCategory android:title="@string/data" >
    <CheckBoxPreference
      android:summary="@string/save_data_summary"
      android:title="@string/save_data_title" />
  </PreferenceCategory>
</PreferenceScreen>

Un écran représentant une interface de préférences commence toujours par la balise PreferenceScreen.

Remarque:

Vous pouvez imbriquer plusieurs balises PreferenceScreen pour avoir plusieurs écrans de préférences imbriqués.

Chaque partie distincte d'une interface de préférences débute par la balise PreferenceCategory. Chaque catégorie peut conten ir un ou plusieurs éléments.

L'exemple abordé possède deux catégories:

Chaque partie distincte d'une interface de préférences débute par la balise PreferenceCategory . Chaque catégorie peut conten ir un ou plusieurs éléments.

L'exemple abordé possède deux catégories:

– La première contient un Switcher.

– La seconde contient une case à cocher.

Remarque:

Tous les éléments qui peuvent composer un écran de préférences possèdent un nom finissant par Preference(SwitchPreference, CheckBoxPreference…).

Modifiez l'activité principale afin d'intégrer le fragment représentant l'écran de préférences :

 
Sélectionnez
@Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
getFragmentManager().beginTransaction().replace(android.
R.id.content, new MyPreferenceFragment()).commit();
  }
   public static class MyPreferenceFragment extends
PreferenceFragment {
    @Override
    public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      addPreferencesFromResource(R.xml.preference_screen);
    }
  }

Dans la méthode onCreate, l'insertion du fragment s'effectue en suivant les étapes ci-dessous:

– Récupérer une instance de la classe FragmentManager, afin d'interagir avec les fragments.

– Appeler la méthode beginTransaction qui permet de commencer une série d'opérations sur un fragment.

– Appeler la méthode replace qui permet d'intégrer la classe personnalisée (MyPreferenceFragment) à l'interface en tant que fragment principal.

– Appeler la méthode commit qui valide toutes les modifications effectuées précédemment.

Puis créez une classe qu i hérite de la classe PreferenceFragment et rajoutez le fragment déclaré dans le fichier XML.

Ce qui donnera:

8. WebView

Le framework Android permet, grâce à la classe WebView, d'inclure des pages HTML à l'intérieur d'une application.

Cette classe utilise le WebKit d'Android pour afficher des pages HTML, l'historique, traiter le code JavaScript, zoomer, etc.

Vous pouvez afficher une page web distante, une page locale stockée dans le projet ou simplement inclure du code HTML.

8-1. Exemple d'une page web distante

La première étape consiste à créer un fichier XML représentant une vue et y inclure le composant WebView.

 
Sélectionnez
<?xml version="1.0" encoding="utf-8"?>
<WebView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/webview"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />

La deuxième étape consiste à créer une activité permettant de lier la vue déclarée précédemment à l'activité et spécifier l'URL à charger par la WebView.

 
Sélectionnez
@Override public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
     
    WebView webView = (WebView) findViewById(R.id.webview);
  webView.loadUrl("http://www.tutos-android.com");
}

Vous pouvez spécifier l'URL à l'aide de la méthode loadUrlaccessible depuis l'instance de la classe WebView.

Sans oublier d'ajouter la permission d'accès à Internet dans le manifeste de l'application:

 
Sélectionnez
<uses-permission android:name="android.permission.INTERNET" />

8-2. Paramètre de la WebView

Vous pouvez accéder aux paramètres d'une WebView afin de la personnaliser grâce à la méthode getSettings.

Voici un exemple servant à récupérer les paramètres d'une WebView afin d'afficher les boutons de zoom (setBuiltInZoomControls) et d'autoriser l'exécution du JavaScript (setJavascriptEnabled).

 
Sélectionnez
WebSettings settings = webView.getSettings();
settings.setBuiltInZoomControls(true);
settings.setJavaScriptEnabled(true);

8-3. Gestion du bouton retour

En incluant des pages Internet dans une application Android, vous devez changer la gestion du bouton retour afin de simuler le comportement du bouton retour d'un navigateur web.

 
Sélectionnez
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
   if ((keyCode == KeyEvent.KEYCODE_BACK) &&
mWebView.canGoBack()) {
    mWebView.goBack();
    return true;
  }
   return super.onKeyDown(keyCode, event);
}

Pour cela, surchargez la méthode onKeyDown. Vérifiez que le clic correspond bien au bouton retour et que la navigation ne se trouve pas à la première page (possibilité d'accéder à une page précédente).

8-4. Utilisation d'Android natif dans du JavaScript

Vous pouvez utiliser du code JavaScript dans des WebView et même combiner ce JavaScript avec du code natif.

Le but de l'exemple suivant est d'afficher un toast Android à l'aide de code JavaScript.

Pour commencer, créez une classe représentant l'interface JavaScript. Elle possédera une méthode permettant d'afficher un Toast.

 
Sélectionnez
public class JavaScriptToastInterface {
   Context context;
   JavaScriptToastInterface(Context c) {
   context = c;
 }
   public void showToast(String toastMsg) {
   Toast.makeText(context, toastMsg, 
Toast.LENGTH_SHORT).show();
 }
}

Activez ensuite le JavaScript dans la WebView et liez l'interface JavaScript à la WebView à l'aide de la méthode addJavascriptInterface.

Le second argument de la méthode correspond à l'identifiant qu'aura cette interface dans le code HTML. Cela vous permet de rajouter plusieurs interfaces JavaScript possédant des identifiants différents.

 
Sélectionnez
WebView webView = (WebView) findViewById(R.id.webview);
WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(true);
webView.addJavascriptInterface(new
JavaScriptToastInterface(this), "Android");
webView.loadData(WEB_CONTENT, "text/html", "UTF-8");

Nous allons avoir besoin d'un contenu web à afficher:

 
Sélectionnez
<input type="button" value="Test Javascript" 
onClick="showAndroidToast('Un Toast cree en Javascript!')" />
<script type="text/javascript">
   function showAndroidToast(toast) {
    Android.showToast(toast);
  }
</script>

Ce bout de code représente un bouton qui exécute la méthode showAndroid présente dans l'interface JavaScript.

Stockez le contenu de ce code HTML dans une variable de type String et chargez le dans la WebView à l'aide de la méthode loadData.

 
Sélectionnez
String WEB_CONTENT = "<input type=\"button\" value=\"Test
Javascript\" onClick=\"showAndroidToast(\'Un toast cree
en Javascript!\')\" /><script type=\"text/javascript\">function
showAndroidToast(toast) {Android.showToast(toast);}</script>";

Ce qui donnera:

9. Bonnes pratiques

Voici quelques conseils afin que vos applications soient adaptables aux différentes situations rencontrées lors du développement d'applications:

9-1. Être indépendant de la résolution de l'écran

– Dans votre application, utilisez les dp(independent pixel ) pour déclarer les tailles des différents éléments et composants ainsi que les sp( independent scale) pour déclarer la taille des différentes polices.

– Créez des dossiers drawable pour chaque résolution (cf. chapitre Création d'interfaces simples - Les ressources).

9-2. Être indépendant de la taille de l'écran

– Pour les différentes tailles d'éléments, privilégiez les tailles prédéfinies(wrap_ontent / match_parent), ce qui permet aux vues de s'adapter aux différentes tailles d'écrans.

– Utilisez le RelativeLayout qui permet de contrôler plus précisément l'emplacement des différents éléments d'une vue les uns par rapport aux autres et non par rapport à la taille de l'écran.

– Créez des layouts pour les différentes tailles d'écrans (small, normal, large, xlarge…) et les positions de l'écran (portrait et paysage).

– Spécifiez les tailles d'écrans gérées à l'aide de la balise supports-screens (cf.chapitre Principes de programmation - Manifeste).

– Utilisez des images étirables (outil 9-patch). L'outil draw9patch fourni avec le SDK Android (dossier tools) permet de spécifier la manière dont une image devra s'étirer selon les cas rencontrés à l'aide de points extensibles à positionner sur l'image cible.

9-3. Être indépendant de la version d'Android utilisée

Certaines API, fonctionnalités ou composants ne sont présents que dans certaines versions d'Android. Pensez à tester la version présente sur l'appareil avant d'utiliser une fonctionnalité qui peut ne pas être disponible sur cette version de l'OS.

 
Sélectionnez
if (Build.VERSION.SDK_INT <
Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
       //Appareil en version 4.0.0 ou supérieur
} else {
    //Appareil en version inférieure à 4.0.0
}

Créez des dossiers spécifiques pour vos interfaces si vous souhaitez personnaliser une interface en fonction des versions d'Android (menu - v14 / values -v11 / layout - v14...).

9-4. Être performant

– Ne créez pas d'objet inutilement.

– Les constantes doivent être statiques (le mot-clé final permet d'indiquer que la valeur stockée dans une variable ne peut être modifiée).

 
Sélectionnez
private static final my_const = 42;

– Évitez les Getters/Setters, préférez les accès directs aux attributs de classe si possible.

– N'utilisez pas n'importe quelle bibliothèque dans une application Android.

10. Optimiser ses interfaces

À chaque création d'une activité, le layout lié à cette activité est chargé (méthode setContentView ou inflate). Ce chargement peut être très coûteux si l'interface en question est mal conçue ou trop lourde. C'est pourquoi Android fournit plusieurs mécanismes afin d'optimiser les différentes interfaces qui composent votre application.

10-1. Inspecter la hiérarchie de ses interfaces

La première méthode pour optimiser des interfaces Android consiste à inspecter la hiérarchie de la vue cible. Pour cela, le SDK Android fournit un outil nommé HierarchyViewer(il se trouve dans le dossier tools du SDK).

Pour utiliser cet outil :
  • Lancez l'application cible sur un émulateur.
  • Affichez l'activité cible (que vous souhaitez inspecter).
  • Lancez le HierarchyViewer.
  • Sélectionnez le processus correspondant à l'application cible, puis cliquez sur Load View Hierarchy.

Un diagramme sur l'interface cible s'affiche.

Voici un exemple simple d'un FrameLayout contenant une image et un texte.

 
Sélectionnez
<?xml version=" 1.0 " encoding="utf-8 "?>
<FrameLayout
xmlns:android=" http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">
  <ImageView 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" 
    android:src="@drawable/ic_launcher" />
  
</FrameLayout>

Ce qui donnera:

L'exécution de l'outil HierarchyViewer sur la vue déclarée précédemment donne le graphique suivant:

Vous pouvez remarquer que le FrameLayout que nous avons déclaré dans la vue suit un autre FrameLayout (ajouté automatiquement par Android lors de la création d'une vue).

La conclusion est que le FrameLayout que nous avons déclaré est inutile et nous pouvons utiliser la balise merge pour fusionner notre vue (sansFrameLayout)avec le FrameLayout déclaré automatiquement (cf. section Fusionner des layouts). Ce qui optimise la vue en évitant de charger un layout inutilement.

10-2. Fusionner des layouts

Android propose le tag merge afin de réduire et d'optimiser le nombre de niveaux d'une interface (cf. exemple précédent). Cette optimisation s'effectue en fusionnant les composants déclarés après le merge avec le layout situé au-dessus du merge.

Appliquez cette optimisation à l'exemple précédent:

 
Sélectionnez
<merge
xmlns:android=" http://schemas.android.com/apk/res/android">
  <ImageView 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" 
    android:scaleType="center"
    android:src="@drawable/ic_launcher" />
</merge>
La balise merge possède quelques limitations :
  • Les layouts fusionnés doivent être identiques ou posséder le même comportement.
  • La balise ne peut être utilisée qu'à la racine d'un fichier XML.
  • Lors de l'utilisation de la balise merge, vous devez spécifier le layout parent sur lequel la vue sera attachée et définir la méthode attachToRoot à vraie.

10-3. Inclure des vues

Vous pouvez modulariser des interfaces afin d'inclure et réutiliser des vues déjà créées dans d'autres vues. Cette fonctionnalité est possible grâce à la balise include fournie par Android.

Lors de l'inclusion, il faut spécifier:

– Un identifiant au layout inclus: afin de pouvoir l'initialiser dans l'activité et récupérer son contenu.

– Le layout à inclure.

L'exemple suivant inclut dans un LinearLayout un autre layout déclaré dans un autre fichier.

 
Sélectionnez

<?xml version=" 1.0 " encoding="utf-8 "?>
<LinearLayout
xmlns:android=" http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical " >
  <include
    android:id="@+id/included_layout "
    layout="@layout/main" />
  <Button
    android:id="@+id/btn "
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/hello " />
</LinearLayout>

10-4. Chargement paresseux (Lazy Loading) des layouts

Le chargement de vue est très coûteux et plus la vue contient d'éléments, plus le temps de chargement est important. Afin de minimiser le nombre de vues chargées à la création d'une interface, vous pouvez utiliser la classe ViewStub.

Un ViewStub utilise un système de chargement paresseux. Un élément de l'interface déclaré à l'aide d'un ViewStub ne sera chargé que lorsque l'élément devient visible.

Voici un exemple d'une interface contenant deux boutons. Le second bouton est déclaré en ViewStub et ne s'affiche qu'au moment du clic sur le premier bouton.

 
Sélectionnez

<?xml version=" 1.0 " encoding="utf-8 "?>
<LinearLayout
xmlns:android=" http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:orientation="vertical " >
  <Button
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:id="@+id/enable"
    android:text="@string/enable_view_stub" />
  <ViewStub
    android:id="@+id/view_stub"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:inflatedId="@+id/view_stub_visible"
    android:layout="@layout/view_stub_btn" />
</LinearLayout>

La déclaration d'un ViewStub se compose ainsi :

– Un identifiant.

– Un identifiant utilisé lorsque la ViewStub sera visible.

– Le layout qui sera chargé par le ViewStub.

Puis déclarez le layout spécifié par le ViewStub:

 
Sélectionnez

<?xml version=" 1.0 " encoding="utf-8 "?>
<Button
xmlns:android=" http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:text="@string/btn_stub" />

Pour finir, il faut récupérer le ViewStub et le rendre visible au moment du clic sur le premier bouton :

 
Sélectionnez
final  View stub = findViewById(R.id.view_stub);
    
Button enable = (Button) findViewById(R.id. enable);
enable.setOnClickListener(new  OnClickListener() {
  @Override 
   public void onClick(View v) {
   stub.setVisibility(View.VISIBLE);
  }
});

Remarque:

Une vue dispose de trois types de visibilité:
  • VISIBLE: la vue devient visible.
  • INVISIBLE : la vue devient invisible mais occupe toujours l'espace qui lui est attribué.
  • GONE: la vue est invisible mais n'occupe plus l'espace qui lui est attribué.