Licence CC BY-NC-SA

Intégrez un menu latéral en Material Design

Dernière mise à jour :
Auteur :
Catégorie :

Ce chapitre aborde plusieurs thématiques divisées en plusieurs sections. La section 1 explique quelle navigation utiliser en fonction de votre situation. Elle ne propose pas une table de correspondance, cela serait impossible d'être exhaustif, mais cela vous fera réfléchir pour pouvoir choisir plus judicieusement la navigation adéquate. La section 2 explique comment l'intégrer dans votre application. La section 3 explique comment placer des items statiques dans le menu, qui n'ont pas vocation à changer par la suite. La section 4 explique comment manipuler ces items en fonction d'un contexte donné. La section 5 est consacrée à une brève conclusion pour résumer tous les points importants à retenir aussi bien sur la navigation par menu latéral que par le choix de ce type de navigation.

Intégrer le menu dans son application

Vous êtes peut-être un développeur Android et vous voulez savoir comment passer des anciens menus latéraux aux nouveaux avec le visuel de la version 5 d'Android, le Material Design. Vous ne serez pas déstabilisé puisque le DrawerLayout est toujours utilisé. Pour les plus débutants, sachez qu'un DrawerLayout est le composant qui vous permet de mettre en place le mécanisme du menu latéral. Il prend deux fils qui correspondent à l'écran principal et au menu latéral.

Avant le Material Design, la mise en oeuvre la plus courante d'un drawer était un FrameLayout comme écran principal pour y placer des fragments1 et une ListView pour le menu latéral. Avec la venue du Material Design, Google a voulu proposer un nouveau composant pour simplifier la gestion de la liste pour le menu et intégrer automatiquement le rendu Material.

Rappelons que le Material Design est apparu avec la version 5 d'Android. Rendre ce rendu le plus possible compatible avec les vieilles versions permet une harmonisation des designs à travers les versions des utilisateurs finaux, chose pas forcément possible avant sans un minimum de travail de la part des développeurs.

Commencez par spécifier les dépendances nécessaires dans le fichier build.gradle de votre application ou module :

1
2
3
compile 'com.android.support:appcompat-v7:24.2.0'
compile 'com.android.support:support-v4:24.2.0'
compile 'com.android.support:design:24.2.0'

Dépendances nécessaires pour le menu latéral et son design

La déclaration d'un écran pour un menu latéral se fait par un layout qui contient un DrawerLayout comme conteneur racine, un NavigationView pour le menu latéral, un FrameLayout pour accueillir les fragments du menu latéral (ou depuis d'autres ressources selon les besoins de votre écran) et une Toolbar qui va accueillir l'icône dite "hamburger" permettant l'ouverture du menu. Notez quand même qu'il reste possible d'ouvrir le menu d'un simple geste de gauche vers la droite.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
  android:id="@+id/drawer_layout"
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:fitsSystemWindows="true"
  tools:context="org.randoomz.demo.design.drawer.DrawerActivity">

  <android.support.design.widget.CoordinatorLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.AppBarLayout
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

      <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:minHeight="?attr/actionBarSize"
        app:layout_collapseMode="pin"/>

    </android.support.design.widget.AppBarLayout>

    <FrameLayout
      android:id="@+id/content"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      app:layout_behavior="@string/appbar_scrolling_view_behavior"/>

  </android.support.design.widget.CoordinatorLayout>

  <android.support.design.widget.NavigationView
    android:id="@+id/nav_view"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    app:headerLayout="@layout/view_header"
    app:menu="@menu/menu_drawer"/>
</android.support.v4.widget.DrawerLayout>

Écran avec un menu latéral

Si vous regardez bien le NavigationView dans l'exemple précédent, celui-ci renseigne deux attributs intéressants. app:headerLayout prend en paramètre un layout pour afficher un espace au dessus de la liste du menu déroulant. L'usage usuel consiste à renseigner le profil de l'utilisateur connecté, ou non. app:menu renseigne le menu que nous voulons remplir dans le menu. Nous verrons sa déclaration dans les sections suivantes de ce chapitre.

Du côté Java, dans l'activité hôte où vous comptez utiliser le layout que vous venez de créer, vous devez initialiser tous ces composants et leurs donner une utilité. C'est ici que les développeurs Android vont avoir de gros changements puisque le menu latéral n'est plus une liste mais un menu, géré comme le menu de la barre d'action sans tous les soucis pour préparer3 un menu s'il est dynamique. Sans se soucier de savoir comment spécifier les items présents dans le menu latéral, il suffit de le récupérer et de lui attacher le listener adéquat pour réagir aux items voulus.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {
  private DrawerLayout drawerLayout;
  private NavigationView navigationView;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);

    navigationView = (NavigationView) findViewById(R.id.nav_view);
    navigationView.setNavigationItemSelectedListener(this);
  }

  @Override public boolean onNavigationItemSelected(@NonNull MenuItem item) {
    Snackbar.make(drawerLayout, item.getTitle(), Snackbar.LENGTH_SHORT).show();
    drawerLayout.closeDrawers();
    return true;
  }
}

Configure la NavigationView dans l'Activity hôte

Cependant, pour permettre de lier l'icône hamburger de la barre d'action, le menu latéral et le DrawerLayout, nous devons utiliser une nouvelle classe, ActionBarDrawerToggle. Cette classe vient lier ces trois composants pour les faire interagir ensemble et permettre de changer l'état du menu facilement. Pour ce faire, vous devez initialiser cette classe aux côtés du DrawerLayout, du NavigationView et de la Toolbar. Puis, renseigner les méthodes de synchronisation dans trois méthodes de l'Activity hôte. Ci-dessous, un exemple concret de sa mise en oeuvre.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_drawer);

  // Get and init DrawerLayout and Toolbar.
  toggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.drawer_open, R.string.drawer_close);
  drawerLayout.addDrawerListener(toggle);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
  if (toggle.onOptionsItemSelected(item)) {
    return true;
  }
  return super.onOptionsItemSelected(item);
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
  super.onConfigurationChanged(newConfig);
  toggle.onConfigurationChanged(newConfig);
}

@Override
protected void onPostCreate(Bundle savedInstanceState) {
  super.onPostCreate(savedInstanceState);
  toggle.syncState();
}

Configuration d'un ActionBarDrawerToggle

Vous remarquerez que l'activité hôte n'étend pas FragmentActivity ou ActionBarActivity mais AppCompatActivity. Cette nouvelle classe est issue de la bibliothèque de compatibilité appcompat-v7 et demande beaucoup de changement dans votre projet notamment dans vos styles et dans l'utilisation de la barre d'action. Toute son utilisation est hors scope de ce tutoriel et en attendant un tutoriel sur Zeste de Savoir, consultez sa documentation pour voir comment l'utiliser. Souvenez vous aussi que tous les exemples donnés dans ce tutoriel sont issus d'une application open source développée spécialement pour ce tutoriel et disponible sur ce projet GitHub. Cela pourrait vous aider à savoir comment gérer vos styles et comment manipuler basiquement la barre d'action avec cette bibliothèque.


  1. Si vous ne savez pas ce que c'est un fragment, je vous redirige vers un autre tutoriel Android qui vous explique tout ce qu'il faut savoir à ce sujet : https://zestedesavoir.com/tutoriels/278/aller-plus-loin-dans-le-developpement-android/ 

  2. Retrouvez l'annonce officiel sur le blog des développeurs Android : http://android-developers.blogspot.fr/2014/12/android-studio-10.html 

  3. Préparer un menu donne la possibilité aux développeurs d'activer/désactiver ou modifier dynamiquement un menu présent dans la barre d'action. 

Menu statique

A partir de cette étape, si vous testez votre application, vous devriez avoir un écran (vide si n'avez attaché aucun fragment) et un menu latéral vide qui s'affiche lorsque vous cliquez sur l'icône en haut à gauche de l'écran ou lorsque vous venez le chercher avec votre doigt sur le bord gauche de l'écran en le glissant vers la droite.

Vous pouvez faire ce que vous voulez de l'écran principal, il ne nous intéresse pas pour ce tutoriel. Par contre, le menu latéral ne va pas rester vide bien longtemps. Nous allons voir la façon "simple" pour ajouter des items dans ce menu. Par simple, j'entends un menu statique pas spécialement voué à changer pendant l'exécution de l'application.

Si vous êtes un développeur Android et que vous avez bien lu toutes mes explications, vous devriez savoir quoi faire. Nous allons simplement créer un fichier XML avec tous les items de notre menu et nous allons l'attacher à notre menu latéral dans son fichier XML. D'ailleurs, pour ce dernier point, c'est déjà fait. Rappelez-vous, nous avons rajouté un schéma par lequel nous pouvons y accéder via app . Puis, nous l'avons utilisé dans NavigationView avec son attribut menu, ce qui donnait la déclaration suivante : app:menu="@menu/drawer_view". Il nous reste donc à créer ce fichier drawer_view dans le dossier menu de votre projet.

Inutile de vous expliquer comment créer des menus, ils ne diffèrent en rien des autres menus d'Android depuis sa version 1. Si vraiment vous ne savez pas comment les créer, allez jeter un oeil à d'autres tutoriels comme ce chapitre du tutoriel Android pour les débutants sur Zeste de Savoir.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
  <group android:checkableBehavior="none">
    <item
      android:id="@+id/menu_add"
      android:icon="@android:drawable/ic_menu_add"
      android:title="@string/menu_add"/>
    <item
      android:id="@+id/menu_delete"
      android:icon="@android:drawable/ic_menu_delete"
      android:title="@string/menu_delete"/>
  </group>
</menu>

Déclaration d'un menu statique

Ce qui est intéressant de constater, c'est le visuel ! Automatiquement, le menu latéral va rajouter nos 2 items dans le menu latéral. Tout se fait en interne de la bibliothèque pour vous simplifiez la vie. N'hésitez pas à jouer avec ses menus pour obtenir le rendu qui vous convient le mieux !

Exemple d'un menu statique

Exemple d'un menu statique

Menu dynamique

Dans 90% des cas, vos besoins se limiteront à des menus statiques mais il peut arriver que vous ayez besoin de modifier dynamiquement les items du menu latéral. Dans ce cas, il faudra utiliser l'API du composant NavigationView consacrée au menu.

Cela serait trop ambitieux de vous expliquer tout ce qu'il est possible de faire puisque la bibliothèque pourrait changer quelques contrats dans son utilisation par rapport au moment où j'ai écrit ces lignes et les possibilités sont bien trop grandes et trop peu intéressantes pour toutes les énumérer. Nous allons donc procéder par l'exemple afin que vous compreniez les mécanismes de cette API et que vous soyez alors capable de les adapter à votre cas d'usage.

Qu'est ce que nous voulons faire ? Nous allons permettre à l'utilisateur de rajouter ou supprimer des items et de les ranger dans une section dédiée du menu latéral. Visuellement, nous voulons une nouvelle section avec un titre et dedans toutes les items de l'utilisateur.

Nous devons faire évoluer le fichier XML du menu pour rajouter une section et un menu :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
  <!-- Previous menu. -->

  <item
    android:id="@+id/menu_dynamic"
    android:title="@string/menu_dynamic">
    <menu>
    </menu>
  </item>
</menu>

Déclaration du menu dynamique

Notez bien l'item avec un identifiant. Cet identifiant est nécessaire pour le récupérer dans le code Java et pour le manipuler. Du côté Java, nous allons réagir aux boutons du menu que nous avons rajouté dans la section précédente. Nous devons rajouter du comportement dans la méthode onNavigationItemSelected(MenuItem) pour créer à la volée des items supplémentaires.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
@Override public boolean onNavigationItemSelected(@NonNull MenuItem item) {
  final MenuItem dynamicItem = navigationView.getMenu().findItem(R.id.menu_dynamic);
  final SubMenu subMenu = dynamicItem.getSubMenu();
  switch (item.getItemId()) {
    case R.id.menu_add:
      subMenu.add(Menu.NONE, subMenu.size(), subMenu.size(), getString(R.string.menu_sub_item, subMenu.size()));
      return true;
    case R.id.menu_delete:
      subMenu.removeItem(subMenu.size() - 1);
      return true;
  }
  Snackbar.make(drawerLayout, item.getTitle(), Snackbar.LENGTH_SHORT).show();
  drawerLayout.closeDrawers();
  return true;
}

Rajoute ou supprime dynamiquement des items du menu latéral

Ce que nous avons fait est très simple. Avec l'instance du menu latéral, nous avons été cherché la nouvelle section par l'identifiant de l'item que nous avons spécifié dans le fichier XML. Puis, nous avons récupéré le menu que contenait la section. Puis, nous ajouter ou supprimons un menu en fonction de ce que l'utilisateur désire faire.

Finalement, nous obtenons un menu latéral avec un menu dynamique. C'est aussi simple que cela et pour les développeurs Android expérimentés, vous remarquez que l'API est semblable à celle de toutes les autres API sur les menus.

Exemple d'un menu dynamique

Exemple d'un menu dynamique


Nous voici à la fin de ce chapitre. Alors, qu'est-ce que vous avez appris ? Malgré le fait que cela soit un modeste mini tutoriel, pas mal de choses. Déjà, vous êtes capable d'intégrer un menu latéral dans votre application ou de mettre à jour votre menu latéral de la liste vers le NavigationView. Vous êtes aussi capable de créer des menus statiques et dynamiques avec ce nouveau composant et donc de vous adapter à toutes les situations. Rien ne vous empêche de concevoir un menu hybride avec du statique et du dynamique, la seule barrière est votre imagination.

Mais plus important, vous avez compris pourquoi et dans quelle situation vous devez utiliser un menu latéral. Pour rappel, un menu latéral est utilisé pour des applications avec des parties distinctes qui n'ont pas forcément de liens entre elles. Vous avez pu le constater avec les exemples mentionnés dans ce tutoriel (repris du projet open source AdvancedAndroidDevelopment sur GitHub) qui possédaient un menu latéral avec différentes sections sans aucun lien entre elles, tout en restant pertinent de les rassembler dans un seul et même composant de navigation.