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 :

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’abscence 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 :

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’impressionante 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!

Trackback

6 commentaires jusqu'à maintenant

  1. et c’est maintenant que tu me dit ça ????
    ça aurait pu me servir dans PRemoteDroid !!!

    :)

  2. Je me permets d’ajouter quelque chose par rapport à la note ci dessus. Les protocoles Objc ne sont pas différents des interfaces Java du fait du caractère runtime de l’objc, car la vérification pourrait être faite à la compilation (et c’est le cas pour @required et non pour @optional). C’est juste que les protocoles ont une philosophie différente, voir étendu des interfaces Java, en permettant le caractère non optionnel. Ainsi protocole objc en required = interface java ;)

  3. Une implémentation à la main à partir de MotionEvent de gestures élaborées comme le drag & drop et le fling est possible, voir par exemple les extraits du livre Hello Android : http://blogs.zdnet.com/Burnette/?p=1747

  4. @staiiff: Bien sûr c’est ce que je fais dans toutes mes applications et ce qui est fait presque partout dans le framework ;). Je voulais simplement, avec cet article, mentionner une classe qui simplifie ou rend facile d’utilisation les gestures au différents développeurs.

  5. maria_patricia @ 2010-03-30 13:26

    Bonjour,
    merci bcp pour tes efforts a nous transmette tes connaissances…
    je suis une stagière actuellement, et mon sujet est d’integrer un client IMS (qui est developpé en C) à Android, et franchement je ne sais pas du tout comment je doit faire ça, surtout que je suis débutante aussi sur Android….si vous pourriez m’aider en me donnant des conseils ou en m’orientant vers des sites internet, je vous serais reconnaissante.
    merci beaucoup pour tout.

  6. Article sympa comme toujours.
    Tu dis que malgré l’existance de cette classe, la plupart des gens implémentent les gestures “à la main” (et notament dans le framework).
    Y a-t’il une raison logique à ça ?

Ajoutez votre commentaire maintenant