I. Introduction▲
Quel est l'avantage des Fragments ? Quand vous développez une application pour smartphones, vous devez faire attention à ne pas surcharger vos Activity, parce que l'écran sur lequel est affiché votre application à une taille réduite. Mais depuis l'arrivée des tablettes, nos applications peuvent s'exécuter sur des écrans plus larges (7", 10"...) et le rendu de la même application fait maintenant vide. Nous allons donc voir comment, sans bouleverser toute l'architecture de votre application, la modifier pour que son rendu sur les ardoises soit plus sympathique. Et nous allons pouvoir faire ça grâce aux Fragments.
II. Étude de cas : LoL Encyclopedia▲
Pour vous montrer quel est l'intérêt pratique de ce tutoriel, voyons une étude de cas (sur l'une de mes applications soit dit en passant). Voici un exemple de cas d'utilisation, chaque écran étant une Activity différente.
Je vous laisse maintenant imaginer la même application sur une tablette : beaucoup d'espace non (ou mal) utilisé.
Voici donc ce que je propose pour améliorer l'ergonomie de l'application. On va réunir ces deux Activity sur un seul et même écran, en affichant à gauche la première Activity (la grille de sélection), et ensuite la partie droite de l'écran se mettra dynamiquement à jour en fonction du choix effectué. Cela évite à l'utilisateur de faire des va-et-vient pour changer son choix, et en plus tout l'écran est occupé, on n'a plus la sensation de vide que l'on pouvait avoir auparavant.
Voyons maintenant comment parvenir à ce résultat.
III. Création des Fragments▲
Typiquement, là où avant vous utilisiez une Activity, et bien maintenant vous allez utiliser en plus un Fragment. L'Activity ne servira plus qu'à afficher le fragment, éventuellement à lui passer les paramètres qu'il a pu recevoir de l'Intent, et c'est à peu près tout. Toute la logique et l'affichage seront faits par le Fragment.
Commençons par modifier notre Activity pour qu'elle utilise un Fragment, mais sans changer le rendu final. Créez une nouvelle classe qui hérite de Fragment, nommez-la comme bon vous semble (personnellement j'utilise le même nom que mon Activity postfixé par "Fragment"). Surchargez sa méthode OnCreateView(), c'est celle que nous allons utiliser pour remplacer le OnCreate() de l'ancienne Activity. Le OnCreate() va juste servir à afficher le Fragment. Dans l'exemple de code suivant, je suppose que mon Activity s'appelle Menu, et que son UI est placée dans le fichier /layout/menu.xml.
Attention, OnCreateView(), contrairement à OnCreate(), doit retourner la vue !
protected
void
onCreate
(
Bundle savedInstanceState)
{
super
.onCreate
(
savedInstanceState);
setContentView
(
R.layout.menu_fragment);
}
public
View onCreateView
(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View mainView =
inflater.inflate
(
R.layout.menu, container, false
);
return
mainView;
}
C'est bien joli tout ça, mais c'est quoi le fichier layout/menu_fragment.xml ? Et bien, c'est un fichier qui décrit votre fragment, à savoir sa taille et la classe associée, et c'est à vous de le créer. Voyez plutôt son contenu.
<?xml version="1.0" encoding="utf-8"?>
<fragment
xmlns
:
android
=
"http://schemas.android.com/apk/res/android"
android
:
name
=
"com.developpez.tutoriel.fragment.MenuFragment"
android
:
layout_width
=
"match_parent"
android
:
layout_height
=
"match_parent"
android
:
id
=
"@+id/menu_fragment"
>
</fragment>
Assez simple non ? Bien évidemment si votre ancienne Actvity a une méthode OnCreate plus complexe, le code précédent le sera lui aussi. Mais le principal est que vous ayez compris le principe.
Si vous lancez votre application maintenant, vous constaterez que visuellement rien n'a changé.
Essayez vraiment de prendre ce réflexe d'architecture, car bien que plus lourd à mettre en oeuvre (deux fois plus de classes/fichiers .xml), il sera bien plus facile d'adapter votre UI à une tablette le jour où vous voudrez le faire.
IV. Affichage parallèle et dialogue▲
Maintenant que vous avez adapté le code de vos Activity que vous souhaitez voir s'exécuter sur le même écran, voyons comment le faire. Pour la suite, mes deux Activity à afficher en parallèle seront nommées Menu et Détail. L'objectif est que lors d'un choix dans Menu, Détail se mette à jour.
Je vais créer une méthode afficherDetail(Uri objet) dans mon Fragment DetailFragment, et qui sera appelée à chaque fois que l'utilisateur choisira un objet. Ce sera cette méthode qui sera chargée de mettre à jour les informations affichées.
Pensez à appeler cette méthode depuis le OnCreate() de votre DetailActivity si jamais un choix est passé dans l'Intent (ce qui sera le cas ici).
Maintenant, je vais ajouter à mon Activity Menu une méthode, onObjetChoisi, qui prendra en paramètre une URI (le nom de l'objet choisi). Lorsque cette méthode sera appelée, elle exécutera (ou mettra à jour) l'Activity Detail.
public
void
onObjetChoisi
(
Uri objet)
{
DetailFragment viewer =
(
DetailFragment) getFragmentManager
(
).findFragmentById
(
R.id.detail_fragment);
// On essaye de récupérer notre fragment.
if
(
viewer ==
null
||
!
viewer.isInLayout
(
))
// S'il n'est pas présent, on le crée en lançant son Activity
{
Intent detailIntent =
new
Intent
(
getApplicationContext
(
), Detail.class
);
detailIntent.setData
(
objet);
startActivity
(
detailIntent);
}
else
// Sinon on met à jour le choix de l'utilisateur
{
viewer.afficherDetail
(
objet);
}
}
Pourquoi une URI ? Parce que la méthode setData de la classe Intent attend en paramètre une URI.
Appelons maintenant notre méthode depuis le Fragment, lorsqu'un clic survient.
public
void
onClic
(
...)
{
//Le code de votre méthode onClic (ou autre)
((
MenuActivity)getActivity
(
)).onObjetChoisi
(
...);
}
Il ne reste plus qu'à configurer l'affichage pour qu'il montre bien les deux Activity côte à côte. Pour cela, modifions le layout associé au menu.
<?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
=
"horizontal"
>
<fragment
android
:
name
=
"com.developpez.tutoriel.fragment.MenuFragment"
android
:
layout_width
=
"0dp"
android
:
layout_height
=
"match_parent"
android
:
id
=
"@+id/menu_fragment"
android
:
layout_weight
=
"30"
>
</fragment>
<fragment
android
:
name
=
"com.developpez.tutoriel.fragment.DetailFragment"
android
:
layout_width
=
"0dp"
android
:
layout_height
=
"match_parent"
android
:
id
=
"@+id/detail_fragment"
android
:
layout_weight
=
"70"
>
</fragment>
</LinearLayout>
Ce type de vue n'étant adapté qu'à l'orientation de type paysage, je vous recommande de placer ce layout dans le dossier /layout-land/, et de prévoir une autre UI pour le mode portrait.
Et voilà ! Vous aurez donc votre Menu affiché à gauche de l'écran, sur 30 % de l'espace disponible, le reste sera pris par Detail dès qu'elle sera affichée, soit après le premier choix effectué dans le menu. Vous remarquerez que le Market de la version Honeycomb d'Android utilise beaucoup ce système, tout comme Gmail, et bien d'autres.
V. Remerciements▲
Je voudrais remercier Claude Leloup pour sa relecture attentive.