Material Design – Toolbar & Drawer

Le Design  Material apporte son lot de modifications du SDK Android afin d’homogénéiser l’ergonomie des applications.

Lorsque l’on parle ergonomie, on parle simplifier la prise en main de notre application par un utilisateur lambda. Cette personne ne doit pas avoir le sentiment d’être perdu dans notre application et doit savoir directement quels actions lui sont disponibles sur l’écran, par exemple quels éléments sont clickables.

Si ce n’est pas encore fait, je vous invite à suivre mon tutoriel d’introduction aux RecyclerView et CardsView, qui introduit par la même le Material Design.

Toolbar

Si vous êtes déjà adepte du développement Android, vous avez déjà utilisé l’ActionBar

actionbar@2x

Pour rappel, l’actionBar, présente en haut de l’écran, permet d’afficher

  • un bouton Retour
  • le nom/l’icône de l’activité
  • le menu

Depuis la version 21 d’AppCompat, l’ActionBar se présente de la forme suivante

device-2015-05-25-150804

 

et je vous présente le rendu d’une, Toolbar :

device-2015-05-25-150804

Bon ok j’ai triché, c’est 2 fois la même image 😀 mais alors quelle est la différence entre ces 2 éléments ? Et bien aucune, à part que la Toolbar est une vue que vous devez déclarer dans le layout de votre activité. Mais pourquoi tout le monde parle de la Toolbar alors ? Je vais vous lister les avantages :

  • Comme c’est une vue, il est possible de la placer où l’on veux dans l’activité (même en bas)
  • Nous pouvons lui ajouter des sous vues, par exemple remplacer le texte par un spinner
  • Comme toute vue, nous pouvons l’animer, la déplacer (la cacher au scroll, etc.)
  • Il n’est plus obligatoire d’utiliser un thème .NoActionBar ou d’utiliser actionbar.hide() si notre acyivité ne doit pas l’afficher

Voici un exemple efficace de l’utilisation de la toolbar (Google IO 2015)

Regardons ensemble comment la mettre en placer, et pourquoi pas comment reproduire l’effet de la vidéo !

Thème

Première étape, utiliser un thème material, je vais ici utiliser AppCompat v7

app/build.gradle

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:22.1.1'
}

1. définir style/Theme.AppCompat.Light en tant que thème parent
2. définir les couleurs de l’application : colorPrimary / colorPrimaryDark / colorAccent
3. désactiver l’actionbar : windowActionBar=false & windowNoTitle=true

res/values/styles.xml

<resources xmlns:tools="http://schemas.android.com/tools">

    <style name="AppBaseTheme" parent="@style/Theme.AppCompat.Light">
    </style>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="AppBaseTheme">

        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>

        <!-- Material Theme -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/accent_color</item>

        <item name="android:statusBarColor" tools:targetApi="21">@color/statusBarColor</item>
        <item name="android:windowDrawsSystemBarBackgrounds" tools:targetApi="21">true</item>

    </style>

</resources>

Voici les couleurs que j’ai utilisé

res/values/colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="blue">#303F9F</color>
    <color name="green">#4CAF50</color>
    <color name="purple">#673AB7</color>
    <color name="cyan">#00BCD4</color>
    <color name="orange">#e95609</color>

    <color name="accent_color">@color/cyan</color>
    <color name="colorPrimary">@color/cyan</color>
    <color name="colorPrimaryDark">@color/cyan</color>
    <color name="statusBarColor">@color/cyan</color>
</resources>

Layout

Il suffit de placer android.support.v7.widget.Toolbar dans votre layout

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

Vous pouvez remarquer que j’utilise ?android:attr/actionBarSize. Cela a pour but d’indiquer à android que la hauteur de la toolbar sera celle fixée en fonction de la version d’Android (recommendations de Google).

exemple :

preview_toolbar

Activité

Il nous faut maintenant récupérer la toolbar, comme c’est une vue nous utiliserons un simple findViewById(), puis l’affecter en tant qu’actionBar de notre activité. Cela permettra de gérer directement le menu et le bouton retour depuis cette toolbar.

 

public class MainActivity extends AppCompatActivity {

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

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

        //definir notre toolbar en tant qu'actionBar
        setSupportActionBar(toolbar);

        //afficher le bouton retour
        getSupportActionBar().setHomeButtonEnabled(true);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    }
    ...
}

device-2015-05-25-221404

 

Animation

Essayons d’animer cette toolbar afin de reproduire l’effet de l’application Google IO 2015

public class MainActivity extends AppCompatActivity {

    Toolbar toolbar;
    View button;

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

        this.toolbar = (Toolbar) findViewById(R.id.toolbar);

        //definir notre toolbar en tant qu'actionBar
        setSupportActionBar(toolbar);

        //afficher le bouton retour
        getSupportActionBar().setHomeButtonEnabled(true);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        this.button = findViewById(R.id.button);
        this.button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                afficherCacherToolbar();
            }
        });
    }

    private void afficherCacherToolbar() {
        if(toolbar.getAlpha() == 1){ //si alpha==1 alors elle est affichee

            //cacher
            toolbar.animate()
                    .alpha(0) //la rendre invisible
                    .translationY(-toolbar.getHeight()) //la déplacer vers le haut
                    .start();
        }
        else{ //si alpha==0 alors elle est cachee

            //afficher
            toolbar.animate()
                    .alpha(1) //la rendre visible
                    .translationY(0) //retour à la position d'origine
                    .start();
        }
    }

}

 

Drawer

Vous aurez du le remarquer dans le titre, je vais aussi vous parler de Drawer, mais qu’est-ce que c’est ?

Si vous avez l’habitude d’utiliser des applications Android, vous avez l’habitude d’ouvrir le menu de l’application en swipant (du verbe swiper, je swipe tu swipe…) à partir de la gauche ou en appuyant sur les 3 traits (aussi appelés Burger Menu)

device-2015-05-25-222924

Ce qui ouvre ce menu, contenant le nom du compte actuellement connecté, ainsi que la liste des différents écrans de l’application.drawer_io

J’en ai parlé lors de l’introduction, Google a mit en place le drawer afin d’homogénéiser les applications, ainsi les utilisateurs ont comme habitude d’utiliser ce menu afin de naviguer entre les écrans de l’application.

Regardons maintenant comment l’implémenter !

<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawerLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

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

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <Button
                android:id="@+id/button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:text="cacher/afficher" />
        </RelativeLayout>

    </LinearLayout>

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="left">

        <include layout="@layout/drawer"/>

    </FrameLayout>

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

Comme vous le voyez, il suffit d’entourer la vue de notre activité par un DrawerLayout

android.support.v4.widget.DrawerLayout

Puis d’ajouter une vue en android:layout_gravity= left, qui sera le contenu de notre Drawer
Dans mon cas je vais définir le layout du drawer dans un autre fichier xml : layout/drawer.xml, puis utiliser include afin qu’il soit injecté ici :

<FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="left">

        <include layout="@layout/drawer"/>

</FrameLayout>

Regardons maintenant du coté de notre activité
Le DrawerLayout se récupère via un findViewById

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

Afin d’ajouter le Burger Menu, rien de plus simple, il suffit d’affecter un ActionBarDrawerToggle en tant que Listener à notre drawerLayout :

drawerToggle = new ActionBarDrawerToggle(this,this.drawerLayout,0,0);
drawerLayout.setDrawerListener(this.drawerToggle);

Puis ne pas oublier d’ajouter ces fonctions à notre activité

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        // synchroniser le drawerToggle après la restauration via onRestoreInstanceState
        drawerToggle.syncState();
    }
    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        drawerToggle.onConfigurationChanged(newConfig);
    }

Voici le résultat

device-2015-05-25-230432

Résumé de l’activité

public class MainActivity extends AppCompatActivity {

    Toolbar toolbar;
    View button;

    DrawerLayout drawerLayout;
    ActionBarDrawerToggle drawerToggle;

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

        this.toolbar = (Toolbar) findViewById(R.id.toolbar);

        //definir notre toolbar en tant qu'actionBar
        setSupportActionBar(toolbar);

        //afficher le bouton retour
        getSupportActionBar().setHomeButtonEnabled(true);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        this.drawerLayout = (DrawerLayout) findViewById(R.id.drawerLayout);
        this.drawerToggle = new ActionBarDrawerToggle(this,this.drawerLayout,0,0);
        this.drawerLayout.setDrawerListener(this.drawerToggle);

        this.button = findViewById(R.id.button);
        this.button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                afficherCacherToolbar();
            }
        });
    }

    //ne pas oublier de copier/coller ces 2 méthodes
    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        // synchroniser le drawerToggle après la restauration via onRestoreInstanceState
        drawerToggle.syncState();
    }
    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        drawerToggle.onConfigurationChanged(newConfig);
    }

    private void afficherCacherToolbar() {
        if(toolbar.getAlpha() == 1){ //si alpha==1 alors elle est affichee

            //cacher
            toolbar.animate()
                    .alpha(0) //la rendre invisible
                    .translationY(-toolbar.getHeight()) //la déplacer vers le haut
                    .start();
        }
        else{ //si alpha==0 alors elle est cachee

            //afficher
            toolbar.animate()
                    .alpha(1) //la rendre visible
                    .translationY(0) //retour à la position d'origine
                    .start();
        }
    }

}

Vous pouvez ajouter des éléments dans votre @layout/drawer.xml et y accéder directement depuis votre activité via un findViewById. Vous pouvez par exemple utiliser une recyclerView dans votre Drawer 😉

Dans mon exemple, j’ai juste placé un TextView

layout/drawer.xml

<?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:background="@android:color/white"
    android:orientation="vertical">

    <TextView
        android:layout_gravity="center"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="20dp"
        android:text="Ceci est le drawer"/>

</LinearLayout>

 

Comme tout bon tutoriel, vous pourrez retrouver les sources à l’adresse suivante : github

N’hésitez pas à nous donner vos avis, ou nous donner des idées de sujets que vous souhaiteriez voir abordé 🙂

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *