• 20 heures
  • Moyenne

Ce cours est visible gratuitement en ligne.

course.header.alt.is_video

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 07/12/2020

Développez votre premier Navigation Drawer

Abordons maintenant un second système de navigation très populaire sur Android : le Navigation Drawer.

Pour cela, nous partirons d'une nouvelle mini-application (MyNavDrawer), afin de voir ensemble et pas à pas le fonctionnement de ce pattern.

Vous trouverez l'application vierge de départ à ce lien.

Introduction

Très récent puisque créé à partir de l'année 2013, le Navigation Drawer combine à lui seul plusieurs patterns que nous avons précédemment étudié. Ce menu de navigation est principalement composé :

  • D'un DrawerLayout, utilisé comme layout racine principal

  • D'une Toolbar, utilisée notamment pour afficher le bouton de navigation "Hamburger"

  • D'une NavigationView, représentant visuellement le menu du Navigation Drawer

  • D'un FrameLayout, contenant les fragments (pages) du Navigation Drawer

Oh la la ! Il y a beaucoup de classes différentes et entremêlées là non ? 

Je dirais plutôt que les choses sont bien découpées... ;) Ne vous inquiétez pas, l'implémentation du Navigation Drawer n'est pas si compliquée, comme nous allons le voir tout de suite !

Implémentation

Reprenons maintenant notre mini-application, MyNavDrawer. Comme vous vous en doutez, nous allons lui créer un Navigation Drawer !

                                                               

Avant toute chose, nous allons vérifier que la librairie Design Support est bien installée et gérée par notre gestionnaire de dépendance Gradle. En effet, la vue NavigationView se trouve à l'intérieur  :

dependencies {
    
    ...
    
    compile 'com.android.support:design:26.1.0'
}

Puis, nous allons modifier le layout de notre activité principale MainActivity afin d'y ajouter les premiers composants graphiques du NavigationDrawer.

Fichier activity_main.xml :

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
    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:id="@+id/activity_main_drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:openDrawer="start"
    tools:context="com.openclassrooms.mynavdrawer.MainActivity">

    <!-- 1 | MainActivity RootView -->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        >

        <!-- Toolbar -->
        <android.support.v7.widget.Toolbar
            android:id="@+id/activity_main_toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:theme="@style/ToolBarStyle"/>

        <!-- FrameLayout for our fragments -->
        <FrameLayout
            android:id="@+id/activity_main_frame_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

    </LinearLayout>

    <!-- 2 | NavigationView -->
    <android.support.design.widget.NavigationView
        android:id="@+id/activity_main_nav_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:fitsSystemWindows="true"
        app:headerLayout="@layout/activity_main_nav_header"
        app:menu="@menu/activity_main_menu_drawer" />

</android.support.v4.widget.DrawerLayout>

Explications : Dans ce layout, nous avons implémenté toutes les vues nécessaires à la création de notre NavigationDrawer :

  • DrawerLayout : Il représente la vue racine principale de notre NavigationDrawer puisqu'il contiendra toutes les sous-vues nécessaires au fonctionnement de ce dernier, comme la Toolbar, le FrameLayout ainsi que le NavigationView.

  • Toolbar : Son intégration au sein du DrawerLayout permettra entre autres, l'affichage et la gestion du bouton de navigation appelé "Hamburger" (les 3 barres horizontales).

  • FrameLayout : Notre conteneur habituel qui contiendra l'ensemble de nos fragments

  • NavigationView : Cette vue représente le menu en lui-même, qui s'affichera ou se cachera lorsqu'on appuiera sur le bouton Hamburger de la Toolbar, et qui contiendra la liste de l'ensemble des pages (fragments) accessibles sur notre application.

Intéressons-nous de plus près à la NavigationView. Cette dernière dispose de deux attributs qui permettront de la configurer assez simplement :

  • app:headerLayout permet de définir, via un layout XML, un header (en-tête) à notre NavigationView

  • app:menu permet de définir, via un layout XML, un menu qui affichera la liste de nos différents écrans sur la NavigationView

                                     

Ces deux attributs pointant sur deux fichiers layouts différents, il faut maintenant penser à les créer... :)

Fichier /res/layout/activity_main_nav_header.xml :

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="@dimen/nav_header_height"
    android:background="#B2B9E1"
    android:gravity="center"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:srcCompat="@drawable/ic_openclassrooms" />

</LinearLayout>

Explications : Rien de compliqué ici, nous créons juste un layout pour le header de notre NavigationView. Nous lui ajoutons une image (que vous pouvez retrouver ici), ainsi qu'une dimension de 176 dip (créée dans le fichier dimens.xml).

Fichier /res/menu/activity_main_menu_drawer.xml :

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    tools:showIn="navigation_view">

    <group android:checkableBehavior="single">
        <item
            android:id="@+id/activity_main_drawer_news"
            android:icon="@drawable/ic_dashboard_white_24dp"
            android:title="Fil d'actualité" />
    </group>

    <item android:title="Configuration">
        <menu>
            <group android:checkableBehavior="single">
                <item
                    android:id="@+id/activity_main_drawer_profile"
                    android:icon="@drawable/ic_account_box_white_24dp"
                    android:title="Profil" />
                <item
                    android:id="@+id/activity_main_drawer_settings"
                    android:icon="@drawable/ic_settings_applications_white_24dp"
                    android:title="Paramètres" />
            </group>
        </menu>
    </item>

</menu>

Explications : Nous définissons ici le menu de notre NavigationView en XML, qui va contenir l'ensemble des pages que l'on souhaite gérer dans notre Navigation Drawer. Chaque item représente une ligne, contenant un titre et une image. Vous pouvez retrouver l'ensemble des icônes utilisées à ce lien.

Pour finir, nous allons modifier quelques fichiers de ressources, afin notamment d'y ajouter la hauteur de l'en-tête de notre NavigationView, et personnaliser notre Toolbar (comme nous avons pu le faire dans les précédents chapitres).

Fichier dimens.xml :

<resources>
    <!-- Default NavigationView Header height -->
    <dimen name="nav_header_height">176dp</dimen>
</resources>

Explications : Cette dimension est utilisée dans le fichier activity_main_nav_header.xml créé précédemment, afin de définir la hauteur de l'en-tête (header) de la NavigationView. C'est la valeur par défaut proposée par Android. Libre à vous ensuite de l'adapter en fonction de vos besoins et vos envies.

Fichier styles.xml :

<resources>
    
     <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

    <!-- Toolbar theme. -->
    <style name="ToolBarStyle" parent="AppTheme">
        <item name="android:textColorPrimary">@android:color/white</item>
        <item name="colorControlNormal">@android:color/white</item>
    </style>
    
</resources>

Explications : Vous vous souvenez sûrement de ces lignes... et c'est normal ! Elles nous servent ici à modifier l'apparence de notre Toolbar, utilisée dans le NavigationDrawer  à travers le layout activity_main.xml. N'oubliez également pas de faire hériter votre thème principal de NoActionBar, afin de masquer la Toolbar par défaut.

Extrait du fichier strings.xml :

<resources>
    
    ...
    
    <!-- Used in NavigationDrawer -->
    <string name="navigation_drawer_open">Open navigation drawer</string>
    <string name="navigation_drawer_close">Close navigation drawer</string>
</resources>

Explications : Ce fichier contient l'ensemble des textes de notre application.  Ces deux lignes nous serviront à la création d'un objet utilisé par le NavigationDrawer. Ne vous inquiétez pas si vous ne le comprenez pas tout de suite, nous y reviendrons en détail dans un autre cours.

Il ne nous manquerait pas quelque chose là ? :-°

Tout à fait ! Car comme d'habitude, qui va faire le lien entre tous ces éléments ? Et bien c'est notre activité MainActivity, bien sûr... ;)

Fichier MainActivity.java :

public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {

    //FOR DESIGN
    private Toolbar toolbar;
    private DrawerLayout drawerLayout;
    private NavigationView navigationView;

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

        // 6 - Configure all views
        
        this.configureToolBar();

        this.configureDrawerLayout();

        this.configureNavigationView();
    }

    @Override
    public void onBackPressed() {
        // 5 - Handle back click to close menu
        if (this.drawerLayout.isDrawerOpen(GravityCompat.START)) {
            this.drawerLayout.closeDrawer(GravityCompat.START);
        } else {
            super.onBackPressed();
        }
    }


    @Override
    public boolean onNavigationItemSelected(MenuItem item) {

        // 4 - Handle Navigation Item Click
        int id = item.getItemId();

        switch (id){
            case R.id.activity_main_drawer_news :
                break;
            case R.id.activity_main_drawer_profile:
                break;
            case R.id.activity_main_drawer_settings:
                break;
            default:
                break;
        }

        this.drawerLayout.closeDrawer(GravityCompat.START);

        return true;
    }

    // ---------------------
    // CONFIGURATION
    // ---------------------

    // 1 - Configure Toolbar
    private void configureToolBar(){
        this.toolbar = (Toolbar) findViewById(R.id.activity_main_toolbar);
        setSupportActionBar(toolbar);
    }

    // 2 - Configure Drawer Layout
    private void configureDrawerLayout(){
        this.drawerLayout = (DrawerLayout) findViewById(R.id.activity_main_drawer_layout);
        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
        drawerLayout.addDrawerListener(toggle);
        toggle.syncState();
    }

    // 3 - Configure NavigationView
    private void configureNavigationView(){
        this.navigationView = (NavigationView) findViewById(R.id.activity_main_nav_view);
        navigationView.setNavigationItemSelectedListener(this);
    }
}

Explications : Notre activité jouant le rôle de contrôleur, celle-ci va récupérer toutes les vues de son layout afin de les configurer et les faire fonctionner harmonieusement ensemble :

  • Ligne 1 : Nous récupérons et configurons la Toolbar.

  • Ligne 2 : Nous récupérons le DrawerLayout, et créons à partir de lui et de la toolbar, le fameux bouton "Hamburger".

  • Ligne 3 : Nous récupérons la NavigationView afin qu'elle puisse s'enregistrer au listener de l'activité (via l'interfaceNavigationView.OnNavigationItemSelectedListener), nous permettant ainsi de récupérer les clics du menu.

  • Ligne 4 : Comme nous avons implémenté l'interface  NavigationView.OnNavigationItemSelectedListener, nous devons déclarer la méthode chargée de récupérer les clics sur le menu, à savoir onNavigationItemSelected. Celle-ci nous permettra, en fonction de l'identifiant d'un item (déclaré dans le fichier activity_main_menu_drawer.xml) du menu, d'effectuer une action spécifique, comme l'affichage d'une page par exemple.

  • Ligne 5 : Nous redéfinissons ici la méthodeonBackPressed() afin de faire en sorte de fermer (s'il est ouvert) le NavigationDrawer, dès lors que l'utilisateur appuie sur la touche retour de son téléphone.

  • Ligne 6 : Enfin, on appelle toutes nos méthodes de configuration depuis la méthode  onCreate()  de notre activité.

Lancez maintenant votre application. Félicitations ! Vous avez un Navigation Drawer parfaitement fonctionnel ^^. 

N'hésitez pas à parcourir un à un l'ensemble des fichiers que nous avons créé, afin de vous familiariser avec la logique du NavigationDrawer. Cette approche et ce fonctionnement sont valables sur énormément de Pattern Android différents. 

Conclusion

Notre navigation Drawer s'affiche correctement et fonctionne plutôt bien, super ! Cependant, lorsque l'on clique sur un élément du menu, rien ne se passe... o_O

Et c'est normal ! Dans le prochain chapitre, nous étudierons ensemble la manière de gérer l'affichage de différentes pages à partir du NavigationDrawer.

Vous pouvez retrouver le code source terminé de MyNavDrawer abordé dans ce chapitre en suivant ce lien.

Exemple de certificat de réussite
Exemple de certificat de réussite