Cyril Mottier

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

Astuce #6 : Les Gestures Faciles…

Les technologies mobiles reposent sur un ensemble de contraintes dont une des principales est probablement le manque d'espace d'affichage. Personnellement, je dois avouer que je prend cette contrainte plutôt comme un avantage car cela me rappelle énormément mes débuts en programmation. A l'époque, je codais en Casio-Basic sur Casio avant d'acquérir une Texas Instrument Voyage 200 et de découvrir le Ti-Basic et surtout le C (aie des pointeurs). L'environnement général me plaisait énormément car je trouvais l'ensemble très puissant (13Mhz) et restreint (pas de threads, pas de multi-processus, etc.). L'écran de cette calculatrice était de taille réduite et monochrome. Remplir cet “amat de pixel” était donc une tâche largement plus simple pour le non-designer que je suis que de réaliser une application PC ou un site web. L'écran n'était malheureusement pas tactile. C'est uniquement lorsque j'ai commencé à coder sur iPhone et Android que j'ai découvert ces possibilités …

Les interfaces mobiles se basent donc sur des concepts ergonomiques et tactiles qui sont absents des plateformes classiques : les gestes (ou gestures). Pour surmonter ces problèmes de tailles de terminal réduit, de nombreux mouvements sont apparus. Les principaux sont donnés dans la liste ci-dessous :

  • Simple click : Consiste à appuyer sur l'écran et à relacher sans avoir bouger son doigt.

  • Double click : Obtenu en effectuant deux clicks au même endroit à la suite. Le temps entre les deux clicks doit également être assez bref.

  • Scroll : Action d'appuyer à l'écran et de déplacer son doigt sans relâcher la pression.

  • Fling : Obtenu lorsqu'on appuie à l'écran, qu'on effectue un mouvement brusque et qu'on relâche rapidement l'écran

  • Long click : Généré en pressant l'écran de façon prolongée et sans bouger

Créer une interface graphique sur Android revient souvent à utiliser l'ensemble de ces gestes. MetroMap utilise par exemple plusieurs d'entre-eux (le simple click, le scroll, et le fling). Lors de la conception de cette application, j'ai décidé d'effectuer manuellement la détection de ces mouvements en utilisant les valeur “standards” d'Android données dans ViewConfiguration. Il existe pourtant une classe qui facilite grandement la reconnaissance de ces gestures : la classe GestureDetector. Son utilisation est on-ne-peut-plus-simple :

MyView.java
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
46
package com.cyrilmottier.android.gesturedetector;

import android.content.Context;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.GestureDetector.OnGestureListener;

public class MyView extends View implements OnGestureListener {

    private GestureDetector mGestureDetector;

    public MyView(Context context) {
        super(context);
        mGestureDetector = new GestureDetector(this);
    }

    public boolean onTouchEvent(MotionEvent event) {
        return mGestureDetector.onTouchEvent(event);
    }

    public boolean onDown(MotionEvent arg0) {
        // Don't forget to return true here to get the following touch events
        return true;
    }

    public boolean onFling(MotionEvent arg0, MotionEvent arg1, float arg2, float arg3) {
        return false;
    }

    public void onLongPress(MotionEvent arg0) {
    }

    public boolean onScroll(MotionEvent arg0, MotionEvent arg1, float arg2, float arg3) {
        // You can do here whatever you want to handle scrolling
        return true;
    }

    public void onShowPress(MotionEvent arg0) {
    }

    public boolean onSingleTapUp(MotionEvent arg0) {
        return false;
    }

}

Implémenter l'interface OnGestureListener oblige le développeur à définir l'intégralité des méthodes (notion de classe abstraite pure). C'est un “problème” inhérent au langage qui n'autorise tout simplement pas les méthode optionnelles d'interface (contrairement à l'Objective-C par exemple) et qui peut être contourné en utilisant une classe qui pré-implémente l'intégralité des méthodes.

Note : Ceux qui s'intéresse à la raison de l'absence des méthode d'interface optionnelle comprendront que la notion d'interface Java est tout simplement vu comme un contrat qui DOIT obligatoirement être respecté. L'Objective-C quant à lui autorise les méthodes d'interface (ou plus précisément de protocole) optionnelles car c'est un langage qui effectue les vérifications au runtime et non à la compilation comme le fait Java.

Android fournit une classe permettant d'effectuer cette manipulation. Si notre code consiste à seulement gérer le scroll, on aura seulement :

MyView.java
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
package com.cyrilmottier.android.gesturedetector;

import android.content.Context;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;

public class MyView extends View {

    private GestureDetector mGestureDetector;

    private GestureDetector.SimpleOnGestureListener mScrollHandler = new GestureDetector.SimpleOnGestureListener() {

        @Override
        public boolean onDown(MotionEvent arg0) {
            // Don't forget to return true here to get the following touch events
            return true;
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            // You can do here whatever you want to handle scrolling
            return true;
        }
    }

    public MyView(Context context) {
        super(context);
        mGestureDetector = new GestureDetector(mScrollHandler);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return mGestureDetector.onTouchEvent(event);
    }

}

Malgré l'impressionnante facilité, la classe GestureDetector ne permet malheureusement pas de détecter l'intégralité des mouvements. On regrette, par exemple, la présence de callbacks sur des mouvements “multi-touch” : le pinch, le rotate, etc. Je suis certain qu'il y a de bonne raison pour cette absence et je ne pourrais donc que motiver les plus courageux à coder leur propre MultitouchGestureDetector. N'hésitez surtout pas à m'informer dans un commentaire ou par courriel si vous développez votre propre librairie. Happy coding!