Module de Programmation Android (LP PRISM AirFrance)
TD6 - Interfaces dynamiques
Les objectifs de ce TD sont :
- la création d'interfaces dynamiques grâce aux fragments ;
- l'interaction entre l'activité et ses fragments.
Pour cela, nous allons revenir sur le jeu "Click the button!", mais avec
cette fois plusieurs fragments au lieu de plusieurs activités.
Mise en place
Commencer une nouvelle application, en choisissant cette
fois Blank Activity with Fragment
au lieu
de Blank Activity
, que l'on pourra par exemple
nommer TD6Activity
.
Observer le code de cette application:
- l'interface de
TD6Activity
contient uniquement le
fragment ;
- l'interface de
TD6ActivityFragment
contient ce qu'on
a habituellement directement dans l'activité:
un RelativeLayout
avec une zone de texte
affichant Hello world!
;
- la classe
TD6ActivityFragment
contient un
constructeur vide (que l'on peut compléter si besoin) et surcharge la
méthode onCreateView
, de manière à charger l'interface
lorsque le fragment est attaché à une activité.
Par défaut, AndroidStudio utilise une ancienne bibliothèque de
fragments, et non celle de la bibliothèque standard. Pour corriger cela,
remplacer dans la liste d'importations
de TD6ActivityFragment
import
android.support.v4.app.Fragment;
par import
android.app.Fragment;
Attachement du fragment au niveau Java
Pour l'instant, le fragment est attaché à
l'activité TD6Activity
lors de la création de celle-ci, et
ne sera détaché que lors de sa destruction. Cela offre l'un des usages
des fragments : le partage d'interfaces entre plusieurs activités. En
revanche, cela ne permet pas d'avoir des interfaces dynamiques : le même
fragment sera en place pendant toute la durée de l'activité.
Pour éviter cela, il faut attacher le fragment au niveau du code Java,
et non dans l'interface XML de l'activité.
- Remplacer l'interface XML actuelle de
TD6Activity
par une boîte LinearLayout
contenant juste une
feuille FrameLayout
. Un FrameLayout
est un
emplacement vide, servant à réserver de la place pour des objets :
c'est là que nous allons attacher notre fragment. Donner un
identifiant au FrameLayout
, comme par
exemple frameLayoutFragment
.
- Ajouter un champ à la classe
TD6Activity
contenant
le fragment que l'on veut utiliser :
private TD6ActivityFragment frag = new
TD6ActivityFragment();
- Ajouter un autre champ qui servira à contenir le gestionnaire de
fragments:
private FragmentManager fragmentManager;
- Initialiser ce champ à la fin de la création de
l'activité (méthode
onCreate
) :
fragmentManager = getFragmentManager();
- Attacher le fragment à la fin du démarrage de l'activité
(méthode
onStart
) :
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.add(R.id.frameLayoutFragment, frag);
transaction.commit();
- Tester.
Attachement et détachement
Avec cette façon d'attacher le fragment, il est maintenant possible de
le détacher et de l'attacher à nouveau, rendant ainsi l'interface plus
dynamique.
Jeu "Click the button!"
Nous allons maintenant implanter notre jeu préféré au sein du fragment.
- Modifier l'interface du fragment pour qu'il contienne un bouton
"Click the button!" et deux zones de texte "Nombre de clics :" et le
nombre effectif, "0" au départ.
- Donner un identifiant au bouton (par
exemple,
buttonClick
) et à la deuxième zone de texte (par
exemple, textViewNbClics
). Récupérer ces vues dans des
champs de la classe TD6ActivityFragment
lors de la
création de la vue liée au fragment, en modifiant la méthode
suivante :
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_td6, container, false);
buttonClick = (Button) v.findViewById(R.id.buttonClick);
textViewNbClics = (TextView) v.findViewById(R.id.textViewNbClics);
return v;
}
Lors de la création de la vu associée au fragment, on génère cette
vue, mais au lieu de la retourner immédiatement comme c'était le cas
auparavant, on récupère d'abord les vues que l'on souhaite.
Pour associer une méthode au clic sur un bouton dans un fragment,
on ne peut pas utiliser l'attribut android:onClick
comme on
le fait lorsque le bouton est directement dans une activité. Il faut
nécessairement passer par la méthode java
correspondante void
setOnClickListener (View.OnClickListener l)
de la
classe Button
qui s'utilise comme suit:
buttonClick.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Action à effectuer
}
});
Le principe est de fournir une implantation de l'interface
Java View.OnClickListener
en implantant sa
méthode void
onClick (View v)
, qui correspond à la méthode qu'on associe
usuellement à l'attribut android:onClick
.
- Associer ainsi au bouton une méthode
onClick
qui
compte le nombre de clics et met la jour la zone de texte
correspondante.
- Tester. Essayer de détacher et attacher le fragment, puis de
cliquer. Que se passe-t-il ? Les clics déjà effectués sont bien
préservés, mais l'affichage lorsqu'on attache le fragment de nouveau
n'est pas correct. Y remédier.
Interaction entre le fragment et l'activité
Le jeu n'est pas encore complet : à chaque fois que l'on a fait cinq
clics, on gagne un niveau. On souhaite que le niveau soit toujours
visible indépendemment du fragment, et donc soit un élément de
l'interface de l'activité et non de celle du fragment.
- Ajouter à l'interface de
TD6Activity
deux zones de
texte "Niveau :" et le niveau effectif, "0" au départ. Attribuer un
identifiant à la deuxième zone (par
exemple textViewNiveau
).
On va vouloir modifier cette zone de texte, non pas dans l'activité,
mais dans le fragment qu'elle contient.
- Récupérer la vue correspondant à la zone de texte dans un champ
de la classe
TD6ActivityFragment
. Pour cela, ajouter à
la méthode onCreateView
:
textViewNiveau = (TextView) getActivity().findViewById(R.id.textViewNiveau);
- Faire en sorte que l'affichage soit mis à jour lorsqu'on gagne un
niveau.
- Tester.
On a ainsi mis à jour des objets de l'activité depuis le fragment. Le
contraire n'est pas possible directement, mais il est possible d'appeler
des méthodes du fragments (qui peuvent mettre à jour des objets de ce
fragment) depuis l'activité.
- Ajouter un bouton "Click the button!" à l'interface de
l'activité.
- Faire en sorte que des clics de l'utilisateur sur ce bouton
augmente le nombre de clics (et donc, le niveau tous les cinq clics)
en appelant sur l'objet
frag
une méthode
de la classe TD6ActivityFragment
(à définir également)
qui va effectuer la mise à jour souhaitée. Attention à factoriser le
code !
- Tester lorsque le fragment est attaché et détaché.
Remarque : On constate que ces interactions entre fragments et activités
peuvent se faire en utilisant directement les objets ou méthodes de l'un
dans l'autre. On rappelle que cela n'est pas possible pour l'interaction
entre activités, pour lesquelles il faut nécessairement passer par des
intentions.
À vous de jouer
- Ajouter à
TD6Activity
un deuxième fragment, qui sera
également un objet de la classe TD6ActivityFragment
(mais
différent de frag
). L'attacher au démarrage de
l'activité.
- Ajouter un deuxième bouton "Attacher/Détacher" pour ce
fragment. Factoriser le code au maximum et tester.
- Ajouter un deuxième bouton "Click the button!" au niveau de
l'activité pour ce fragment. Factoriser le code au maximum et
tester.
- Comment réagit le niveau aux clics sur les différents boutons ?
Faire en sorte qu'on gagne un niveau à chaque fois que la somme
des deux nombres de clics est multiple de 5.
Remarque : on rappelle l'existence du
mot-clé static
...
- Observer le comportement de l'activité lorsqu'on tourne la
tablette. Le corriger.
Retour à la page du cours |