Un geste tactile se produit lorsqu'un utilisateur place un ou plusieurs doigts sur l'écran tactile et que votre application interprète ce schéma de gestes comme un geste. La détection des gestes se déroule en deux phases:
- Collecte des données d'événements tactiles...
- L'interprétation des données pour déterminer si elles répondent aux critères des gestes compatibles avec votre application.
Classes AndroidX
Les exemples de ce document utilisent les classes GestureDetectorCompat
et MotionEventCompat
. Ces classes se trouvent dans la bibliothèque AndroidX. Dans la mesure du possible, utilisez les classes AndroidX pour assurer la compatibilité avec les appareils plus anciens.
MotionEventCompat
ne remplace pas la classe MotionEvent
. Il fournit plutôt des méthodes utilitaires statiques auxquelles vous transmettez votre objet MotionEvent
pour recevoir l'action associée à cet événement.
Recueillir des données
Lorsqu'un utilisateur place un ou plusieurs doigts sur l'écran, le rappel onTouchEvent()
est déclenché sur la vue qui reçoit les événements tactiles. Pour chaque séquence d'événements tactiles (position, pression, taille et ajout d'un autre doigt, par exemple) identifiée comme un geste, onTouchEvent()
est déclenché plusieurs fois.
Le geste commence lorsque l'utilisateur touche l'écran pour la première fois, se poursuit à mesure que le système suit la position du ou des doigts de l'utilisateur, et se termine en capturant l'événement final du dernier doigt de l'utilisateur quittant l'écran.
Tout au long de cette interaction, le MotionEvent
envoyé à onTouchEvent()
fournit les détails de chaque interaction. Votre application peut utiliser les données fournies par MotionEvent
pour déterminer si un geste qui lui tient à cœur se produit.
Enregistrer des événements tactiles pour une activité ou une vue
Pour intercepter des événements tactiles dans un Activity
ou un View
, remplacez le rappel onTouchEvent()
.
L'extrait de code suivant utilise getAction()
pour extraire l'action effectuée par l'utilisateur à partir du paramètre event
.
Vous obtenez ainsi les données brutes dont vous avez besoin pour déterminer si un geste qui vous intéresse se produit.
Kotlin
class MainActivity : Activity() { ... // This example shows an Activity. You can use the same approach if you are // subclassing a View. override fun onTouchEvent(event: MotionEvent): Boolean { return when (event.action) { MotionEvent.ACTION_DOWN -> { Log.d(DEBUG_TAG, "Action was DOWN") true } MotionEvent.ACTION_MOVE -> { Log.d(DEBUG_TAG, "Action was MOVE") true } MotionEvent.ACTION_UP -> { Log.d(DEBUG_TAG, "Action was UP") true } MotionEvent.ACTION_CANCEL -> { Log.d(DEBUG_TAG, "Action was CANCEL") true } MotionEvent.ACTION_OUTSIDE -> { Log.d(DEBUG_TAG, "Movement occurred outside bounds of current screen element") true } else -> super.onTouchEvent(event) } } }
Java
public class MainActivity extends Activity { ... // This example shows an Activity. You can use the same approach if you are // subclassing a View. @Override public boolean onTouchEvent(MotionEvent event){ switch(event.getAction()) { case (MotionEvent.ACTION_DOWN) : Log.d(DEBUG_TAG,"Action was DOWN"); return true; case (MotionEvent.ACTION_MOVE) : Log.d(DEBUG_TAG,"Action was MOVE"); return true; case (MotionEvent.ACTION_UP) : Log.d(DEBUG_TAG,"Action was UP"); return true; case (MotionEvent.ACTION_CANCEL) : Log.d(DEBUG_TAG,"Action was CANCEL"); return true; case (MotionEvent.ACTION_OUTSIDE) : Log.d(DEBUG_TAG,"Movement occurred outside bounds of current screen element"); return true; default : return super.onTouchEvent(event); } }
Ce code génère des messages semblables à ce qui suit dans Logcat lorsque l'utilisateur appuie, appuie de manière prolongée et fait glisser:
GESTURES D Action was DOWN GESTURES D Action was UP GESTURES D Action was MOVE
Pour les gestes personnalisés, vous pouvez ensuite traiter ces événements vous-même pour déterminer s'ils représentent un geste que vous devez gérer. Toutefois, si votre application utilise des gestes courants (appuyer deux fois, appuyer de manière prolongée, faire glisser l'écran, etc.), vous pouvez utiliser la classe GestureDetector
. GestureDetector
vous permet de détecter plus facilement les gestes courants sans traiter vous-même les événements tactiles individuels. Ce point est abordé plus en détail dans la section Détecter les gestes.
Capturer des événements tactiles pour une vue unique
Au lieu de onTouchEvent()
, vous pouvez associer un objet View.OnTouchListener
à n'importe quel objet View
à l'aide de la méthode setOnTouchListener()
. Cela permet d'écouter des événements tactiles sans sous-classer un View
existant, comme illustré dans l'exemple suivant:
Kotlin
findViewById<View>(R.id.my_view).setOnTouchListener { v, event -> // Respond to touch events. true }
Java
View myView = findViewById(R.id.my_view); myView.setOnTouchListener(new OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { // Respond to touch events. return true; } });
Veillez à créer un écouteur qui renvoie false
pour l'événement ACTION_DOWN
.
Dans ce cas, l'écouteur n'est pas appelé pour la séquence d'événements ACTION_MOVE
et ACTION_UP
suivantes. En effet, ACTION_DOWN
est le point de départ de tous les événements tactiles.
Si vous créez une vue personnalisée, vous pouvez remplacer onTouchEvent()
, comme décrit précédemment.
Détecter les gestes
Android fournit la classe GestureDetector
permettant de détecter les gestes courants. onDown()
, onLongPress()
et onFling()
font partie des gestes qu'il accepte.
Vous pouvez utiliser GestureDetector
conjointement avec la méthode onTouchEvent()
décrite précédemment.
Détecter tous les gestes compatibles
Lorsque vous instanciez un objet GestureDetectorCompat
, l'un des paramètres requis est une classe qui implémente l'interface GestureDetector.OnGestureListener
. GestureDetector.OnGestureListener
avertit les utilisateurs lorsqu'un événement tactile particulier se produit. Pour que votre objet GestureDetector
puisse recevoir des événements, ignorez la méthode onTouchEvent()
de la vue ou de l'activité, et transmettez tous les événements observés à l'instance de détecteur.
Dans l'extrait de code suivant, une valeur true
renvoyée par les méthodes on<TouchEvent>
individuelles indique que l'événement tactile est géré. La valeur renvoyée false
transmet les événements via la pile d'affichage jusqu'à ce que l'appui soit géré.
Si vous exécutez l'extrait suivant dans une application de test, vous pouvez avoir une idée de la façon dont les actions sont déclenchées lorsque vous interagissez avec l'écran tactile et du contenu de MotionEvent
pour chaque événement tactile. Vous verrez ensuite la quantité de données générées pour des interactions simples.
Kotlin
private const val DEBUG_TAG = "Gestures" class MainActivity : Activity(), GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener { private lateinit var mDetector: GestureDetectorCompat // Called when the activity is first created. public override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // Instantiate the gesture detector with the // application context and an implementation of // GestureDetector.OnGestureListener. mDetector = GestureDetectorCompat(this, this) // Set the gesture detector as the double-tap // listener. mDetector.setOnDoubleTapListener(this) } override fun onTouchEvent(event: MotionEvent): Boolean { return if (mDetector.onTouchEvent(event)) { true } else { super.onTouchEvent(event) } } override fun onDown(event: MotionEvent): Boolean { Log.d(DEBUG_TAG, "onDown: $event") return true } override fun onFling( event1: MotionEvent, event2: MotionEvent, velocityX: Float, velocityY: Float ): Boolean { Log.d(DEBUG_TAG, "onFling: $event1 $event2") return true } override fun onLongPress(event: MotionEvent) { Log.d(DEBUG_TAG, "onLongPress: $event") } override fun onScroll( event1: MotionEvent, event2: MotionEvent, distanceX: Float, distanceY: Float ): Boolean { Log.d(DEBUG_TAG, "onScroll: $event1 $event2") return true } override fun onShowPress(event: MotionEvent) { Log.d(DEBUG_TAG, "onShowPress: $event") } override fun onSingleTapUp(event: MotionEvent): Boolean { Log.d(DEBUG_TAG, "onSingleTapUp: $event") return true } override fun onDoubleTap(event: MotionEvent): Boolean { Log.d(DEBUG_TAG, "onDoubleTap: $event") return true } override fun onDoubleTapEvent(event: MotionEvent): Boolean { Log.d(DEBUG_TAG, "onDoubleTapEvent: $event") return true } override fun onSingleTapConfirmed(event: MotionEvent): Boolean { Log.d(DEBUG_TAG, "onSingleTapConfirmed: $event") return true } }
Java
public class MainActivity extends Activity implements GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener{ private static final String DEBUG_TAG = "Gestures"; private GestureDetectorCompat mDetector; // Called when the activity is first created. @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Instantiate the gesture detector with the // application context and an implementation of // GestureDetector.OnGestureListener. mDetector = new GestureDetectorCompat(this,this); // Set the gesture detector as the double-tap // listener. mDetector.setOnDoubleTapListener(this); } @Override public boolean onTouchEvent(MotionEvent event){ if (this.mDetector.onTouchEvent(event)) { return true; } return super.onTouchEvent(event); } @Override public boolean onDown(MotionEvent event) { Log.d(DEBUG_TAG,"onDown: " + event.toString()); return true; } @Override public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) { Log.d(DEBUG_TAG, "onFling: " + event1.toString() + event2.toString()); return true; } @Override public void onLongPress(MotionEvent event) { Log.d(DEBUG_TAG, "onLongPress: " + event.toString()); } @Override public boolean onScroll(MotionEvent event1, MotionEvent event2, float distanceX, float distanceY) { Log.d(DEBUG_TAG, "onScroll: " + event1.toString() + event2.toString()); return true; } @Override public void onShowPress(MotionEvent event) { Log.d(DEBUG_TAG, "onShowPress: " + event.toString()); } @Override public boolean onSingleTapUp(MotionEvent event) { Log.d(DEBUG_TAG, "onSingleTapUp: " + event.toString()); return true; } @Override public boolean onDoubleTap(MotionEvent event) { Log.d(DEBUG_TAG, "onDoubleTap: " + event.toString()); return true; } @Override public boolean onDoubleTapEvent(MotionEvent event) { Log.d(DEBUG_TAG, "onDoubleTapEvent: " + event.toString()); return true; } @Override public boolean onSingleTapConfirmed(MotionEvent event) { Log.d(DEBUG_TAG, "onSingleTapConfirmed: " + event.toString()); return true; } }
Détecter un sous-ensemble de gestes compatibles
Si vous ne souhaitez traiter que quelques gestes, vous pouvez étendre GestureDetector.SimpleOnGestureListener
au lieu d'implémenter l'interface GestureDetector.OnGestureListener
.
GestureDetector.SimpleOnGestureListener
fournit une implémentation pour toutes les méthodes on<TouchEvent>
en renvoyant false
pour toutes. Cela vous permet de ne remplacer que les méthodes qui vous intéressent. Par exemple, l'extrait de code suivant crée une classe qui étend GestureDetector.SimpleOnGestureListener
, et remplace onFling()
et onDown()
.
Que vous utilisiez GestureDetector.OnGestureListener
ou GestureDetector.SimpleOnGestureListener
, il est recommandé d'implémenter une méthode onDown()
qui renvoie true
. En effet, tous les gestes commencent par un message onDown()
. Si vous renvoyez false
à partir de onDown()
, comme GestureDetector.SimpleOnGestureListener
par défaut, le système suppose que vous souhaitez ignorer le reste du geste et les autres méthodes de GestureDetector.OnGestureListener
ne sont pas appelées. Cela peut entraîner des problèmes inattendus dans votre application. Ne renvoyez false
à partir de onDown()
que si vous souhaitez vraiment ignorer un geste entier.
Kotlin
private const val DEBUG_TAG = "Gestures" class MainActivity : Activity() { private lateinit var mDetector: GestureDetectorCompat public override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) mDetector = GestureDetectorCompat(this, MyGestureListener()) } override fun onTouchEvent(event: MotionEvent): Boolean { mDetector.onTouchEvent(event) return super.onTouchEvent(event) } private class MyGestureListener : GestureDetector.SimpleOnGestureListener() { override fun onDown(event: MotionEvent): Boolean { Log.d(DEBUG_TAG, "onDown: $event") return true } override fun onFling( event1: MotionEvent, event2: MotionEvent, velocityX: Float, velocityY: Float ): Boolean { Log.d(DEBUG_TAG, "onFling: $event1 $event2") return true } } }
Java
public class MainActivity extends Activity { private GestureDetectorCompat mDetector; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mDetector = new GestureDetectorCompat(this, new MyGestureListener()); } @Override public boolean onTouchEvent(MotionEvent event){ if (this.mDetector.onTouchEvent(event)) { return true; } return super.onTouchEvent(event); } class MyGestureListener extends GestureDetector.SimpleOnGestureListener { private static final String DEBUG_TAG = "Gestures"; @Override public boolean onDown(MotionEvent event) { Log.d(DEBUG_TAG,"onDown: " + event.toString()); return true; } @Override public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) { Log.d(DEBUG_TAG, "onFling: " + event1.toString() + event2.toString()); return true; } } }
Ressources supplémentaires
- Présentation des événements d'entrée
- Présentation des capteurs
- Rendre une vue personnalisée interactive