Cyril Mottier

“It’s the little details that are vital. Little things make big things happen.” – John Wooden

Utilisation Des SlidingDrawers

La programmation sur terminaux mobiles est régie par de nombreuses contraintes souvent inhérentes à l'accès à des ressources limitées : puissance processeur faible, quantité de mémoire disponible limitée, durée de vie de la batterie courte, bande-passante faible, etc. La réalisation d'interfaces graphiques met rapidement en évidence un autre problème du développement sur OS mobiles : une taille d'écran relativement petite. Les designers sont donc confrontés à des problèmes d'agencements de l'information et des widgets dans l'interface. Il sont, de plus, contraints à utiliser des éléments graphiques de taille assez conséquente afin que ces derniers puisse être activés au toucher. Conserver la facilité d'utilisation et l'ergonomie d'une interface mobile passe donc souvent par la suppression d'éléments dans l'interface.

Android 1.5 introduit un widget, déjà connu de beaucoup d'utilisateurs, permettant de résoudre partiellement le problème : le SlidingDrawer. Cet élément graphique avait fait son apparition à la première release d'Android dans le HomeScreen mais n'était pas disponible en tant que widget dans l'API Android. Ce widget se comporte comme un tiroir : tirer ou cliquer sur la poignée provoque son ouverture et affiche alors l'ensemble des éléments présents à l'intérieur comme dans la figure ci-dessous. Cela permet de ranger des éléments non essentiel au premier abord tout en les conservant à portée de main.

L'utilisation de ce SlidingDrawer est relativement aisée et consiste à définir une interface du type :

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
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <View
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="#ffff00" />

    <SlidingDrawer
        android:id="@+id/drawer"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:content="@+id/content"
        android:handle="@+id/handle"
        android:orientation="vertical" >

        <ImageView
            android:id="@+id/handle"
            android:layout_width="88dip"
            android:layout_height="44dip"
            android:background="#00ff00"
            android:src="@drawable/arrow" />

        <GridView
            android:id="@+id/content"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:background="#fff" />
    </SlidingDrawer>

</FrameLayout>

Comme le montre le code précédent, l'instanciation d'un SlidingDrawer se fait par XML (il n'est pas possible de créer un SlidingDrawer de façon manuelle ou difficilement) en définissant 2 vues filles qui représente le handle (la poignée) et le content (le contenu). Les attributs android:handle et android:content permettant de préciser au SlidingDrawer les vues handle et content sont obligatoires.

Les options disponibles sur le widget SlidingDrawer ne sont pas nombreuses mais offre de belles perspectives :

  • android:orientation : définit l'orientation horizontale ou verticale. Le sliding drawer “glissera” alors de bas en haut (horizontale) ou de droite à gauche (verticale).

  • android:topOffset & android:bottomOffset : permettent de définir des marges en haut et en bas du drawer.

  • android:allowSingleTap & android:animateOnClick : permet d'activer ou non l'ouverture du SlidingDrawer par un clic sur la poignée et d'activer ou non l'animation à l'ouverture/fermeture.

Il est enfin possible de suivre l'évolution du SlidingDrawer et ainsi de déterminer si ce dernier est ouvert, fermé, etc. Pour ce faire le widget fournit les méthodes isOpen() et isMoving() ainsi qu'un ensemble de listeners : SlidingDrawer.OnDrawerCloseListener, SlidingDrawer.OnDrawerOpenListener et SlidingDrawer.OnDrawerScrollListener.

L'ajout de ce nouvel élément graphique va très probablement apporter de nombreux améliorations dans les futures interfaces graphiques des applications Android. Je regrette néanmoins l'absence de certaines options ou l'incohérence des méthodes. En effet, il est impossible de faire en sorte qu'un SlidingDrawer glisse de bas en haut. Un attribut android:handleGravity permettant de positionner la poignée à droite, à gauche ou au centre fait également défaut (même si il semble difficile de justifier une position qui varie en fonction de l'orientation : “gauche” devenant “bas” par exemple). On aurait également pu définir des SlidingDrawer multiple (en association avec la méthode bringChildToFront(View child) de ViewGroup afin de s'assurer du bon “empilement” des vues dans le FrameLayout ou RelativeLayout englobant.

Je déplore enfin le système de listeners associé à SlidingDrawer. Les listeners se décomposent en effet en 3 interfaces différentes ce qui n'est pas, à mon humble avis, Android-friendly. Il aurait été préférable de définir un listener global définit ci-dessous et permettant la gestion multiple de SlidingDrawers dans une même classe :

OnDrawerChangeListener.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public interface OnDrawerChangeListener {
    /**
     * Invoked when the drawer becomes fully open.
     */
    public void onDrawerOpened(SlidingDrawer drawer);

    /**
     * Invoked when the drawer becomes fully closed.
     */
    public void onDrawerClosed(SlidingDrawer drawer);

    /**
     * Invoked when the user starts dragging/flinging the drawer's handle.
     */
    public void onScrollStarted(SlidingDrawer drawer);

    /**
     * Invoked when the user stops dragging/flinging the drawer's handle.
     */
    public void onScrollEnded(SlidingDrawer drawer);
}

Je pense que l'équipe de développement des widgets Android a longuement réfléchit à ce problème et a considéré qu'un SlidingDrawer ne devait être qu'unique dans une même Activity. L'ajout d'un paramètre mentionnant quel SlidingDrawer a changé est dans ce cas inutile.