Concepts clés

Les sections suivantes décrivent quelques concepts clés du processus de glisser-déposer.

Processus de glisser-déposer

Le processus de glisser-déposer comporte quatre étapes ou états: démarré, continu, abandonné et terminé.

Date de lancement

En réponse au geste de déplacement d'un utilisateur, votre application appelle startDragAndDrop() pour indiquer au système de lancer une opération de glisser-déposer. Les arguments de la méthode fournissent les éléments suivants:

  • Données à faire glisser.
  • Rappel permettant de dessiner l'ombre de déplacement
  • Métadonnées décrivant les données déplacées
  • Le système répond en rappelant votre application pour obtenir une ombre de déplacement. Le système affiche ensuite l'ombre du glissement sur l'appareil.
  • Ensuite, le système envoie un événement de déplacement avec le type d'action ACTION_DRAG_STARTED à l'écouteur d'événements de déplacement de tous les objets View de la mise en page actuelle. Pour continuer à recevoir des événements de déplacement, y compris un événement de déplacement potentiel, l'écouteur d'événements de déplacement doit renvoyer true. L'écouteur est alors enregistré auprès du système. Seuls les écouteurs enregistrés continuent de recevoir des événements de déplacement. À ce stade, les écouteurs peuvent également modifier l'apparence de leur objet "déposer" View pour indiquer que la vue peut accepter un événement de dépôt.
  • Si l'écouteur d'événements de déplacement renvoie false, il ne reçoit pas d'événements de déplacement pour l'opération en cours tant que le système n'a pas envoyé un événement de déplacement de type d'action ACTION_DRAG_ENDED. En renvoyant false, l'écouteur indique au système qu'il n'est pas intéressé par l'opération de glisser-déposer et qu'il ne veut pas accepter les données déplacées.
Poursuite de l'opération…
L'utilisateur poursuit son déplacement. Lorsque l'ombre de déplacement rencontre le cadre de délimitation d'une cible de dépôt, le système envoie un ou plusieurs événements de déplacement à l'écouteur d'événements de déplacement de la cible. L'écouteur peut modifier l'apparence de la cible de dépôt View en réponse à l'événement. Par exemple, si l'événement indique que l'ombre du déplacement entre dans le cadre de délimitation de la cible de dépôt (type d'action ACTION_DRAG_ENTERED), l'écouteur peut réagir en mettant en surbrillance View.
Déplacé
L'utilisateur libère l'ombre du déplacement dans le cadre de délimitation d'une cible de dépôt. Le système envoie à l'écouteur de la cible de dépôt un événement de déplacement avec le type d'action ACTION_DROP. L'objet d'événement de déplacement contient les données qui sont transmises au système dans l'appel à startDragAndDrop() qui lance l'opération. L'écouteur doit renvoyer la valeur booléenne true au système s'il traite correctement les données supprimées. Cette étape ne se produit que si l'utilisateur dépose l'ombre de déplacement dans la zone de délimitation d'un View dont l'écouteur est enregistré pour recevoir des événements de déplacement (une cible de dépôt). Si l'utilisateur lève l'ombre de déplacement dans toute autre situation, aucun événement de déplacement ACTION_DROP n'est envoyé.
Terminé

Une fois que l'utilisateur a libéré l'ombre du déplacement et après que le système a envoyé

un événement de déplacement de type ACTION_DROP. Si nécessaire, le système envoie un événement de déplacement de type ACTION_DRAG_ENDED pour indiquer que l'opération de glisser-déposer est terminée. Cela se fait quel que soit l'endroit où l'utilisateur libère l'ombre du déplacement. L'événement est envoyé à chaque écouteur enregistré pour recevoir des événements de déplacement, même s'il reçoit également l'événement ACTION_DROP.

Chacune de ces étapes est décrite plus en détail dans la section Opération de glisser-déposer.

Événements de déplacement

Le système envoie un événement de déplacement sous la forme d'un objet DragEvent, qui contient un type d'action décrivant le processus de glisser-déposer. Selon le type d'action, l'objet peut également contenir d'autres données.

Les écouteurs d'événements de déplacement reçoivent l'objet DragEvent. Pour obtenir le type d'action, les écouteurs appellent DragEvent.getAction(). Six valeurs possibles sont définies par des constantes dans la classe DragEvent, décrites dans le tableau 1:

Tableau 1. Types d'actions DragEvent

Type d'action Signification
ACTION_DRAG_STARTED L'application appelle startDragAndDrop() et obtient une ombre de déplacement. Si l'écouteur souhaite continuer à recevoir des événements de déplacement pour cette opération, il doit renvoyer la valeur booléenne true au système.
ACTION_DRAG_ENTERED L'ombre de déplacement entre dans le cadre de délimitation du View de l'écouteur d'événements de déplacement. Il s'agit du premier type d'action d'événement que l'écouteur reçoit lorsque l'ombre du déplacement entre dans la zone de délimitation.
ACTION_DRAG_LOCATION Après un événement ACTION_DRAG_ENTERED, l'ombre de déplacement reste dans le cadre de délimitation du View de l'écouteur d'événements de déplacement.
ACTION_DRAG_EXITED Après un événement ACTION_DRAG_ENTERED et au moins un événement ACTION_DRAG_LOCATION, l'ombre de déplacement se déplace en dehors du cadre de délimitation du View de l'écouteur d'événements de déplacement.
ACTION_DROP L'ombre de déplacement se relâche au-dessus du View de l'écouteur d'événements de déplacement. Ce type d'action n'est envoyé à l'écouteur d'un objet View que s'il renvoie la valeur booléenne true en réponse à l'événement de déplacement ACTION_DRAG_STARTED. Ce type d'action n'est pas envoyé si l'utilisateur libère l'ombre de déplacement sur un View dont l'écouteur n'est pas enregistré ou s'il libère l'ombre de déplacement sur tout élément qui ne fait pas partie de la mise en page actuelle.

L'écouteur renvoie la valeur booléenne true s'il traite correctement la suppression. Sinon, elle doit renvoyer false.

ACTION_DRAG_ENDED Le système met fin à l'opération de glisser-déposer. Ce type d'action n'est pas nécessairement précédé d'un événement ACTION_DROP. Si le système envoie un ACTION_DROP, la réception du type d'action ACTION_DRAG_ENDED n'implique pas que la suppression a réussi. L'écouteur doit appeler getResult(), comme indiqué dans le tableau 2, pour obtenir la valeur renvoyée en réponse à ACTION_DROP. Si aucun événement ACTION_DROP n'est envoyé, getResult() renvoie false.

L'objet DragEvent contient également les données et les métadonnées fournies par votre application au système dans l'appel de startDragAndDrop(). Certaines données ne sont valides que pour certains types d'actions, comme résumé dans le tableau 2. Pour en savoir plus sur les événements et les données associées, consultez la section intitulée Une opération de glisser-déposer.

Tableau 2. Données DragEvent valides par type d'action

Valeur de getAction()
Valeur de getClipDescription()
Valeur de getLocalState()
Valeur de getX()
Valeur de getY()
Valeur de getClipData()
Valeur de getResult()
ACTION_DRAG_STARTED &coche; &coche;        
ACTION_DRAG_ENTERED &coche; &coche;        
ACTION_DRAG_LOCATION &coche; &coche; &coche; &coche;    
ACTION_DRAG_EXITED &coche; &coche;        
ACTION_DROP &coche; &coche; &coche; &coche; &coche;  
ACTION_DRAG_ENDED   &coche;       &coche;

Les méthodes DragEvent getAction(), describeContents(), writeToParcel() et toString() renvoient toujours des données valides.

Si une méthode ne contient pas de données valides pour un type d'action particulier, elle renvoie null ou 0, en fonction de son type de résultat.

Ombre de déplacement

Lors d'une opération de glisser-déposer, le système affiche une image que l'utilisateur fait glisser. Pour les mouvements de données, cette image représente les données en cours de déplacement. Pour les autres opérations, l'image représente un aspect de l'opération de déplacement.

Il s'agit d'une ombre du déplacement. Vous le créez à l'aide de méthodes que vous déclarez pour un objet View.DragShadowBuilder. Vous transmettez le compilateur au système lorsque vous démarrez une opération de glisser-déposer à l'aide de startDragAndDrop(). Dans le cadre de sa réponse à startDragAndDrop(), le système appelle les méthodes de rappel que vous définissez dans View.DragShadowBuilder pour obtenir une ombre de déplacement.

La classe View.DragShadowBuilder comporte deux constructeurs:

View.DragShadowBuilder(View)

Ce constructeur accepte tous les objets View de votre application. Le constructeur stocke l'objet View dans l'objet View.DragShadowBuilder afin que les rappels puissent y accéder pour construire l'ombre de déplacement. La vue ne doit pas nécessairement être un View sélectionné par l'utilisateur pour lancer l'opération de déplacement.

Si vous utilisez ce constructeur, vous n'avez pas besoin d'étendre View.DragShadowBuilder ni de remplacer ses méthodes. Par défaut, vous obtenez une ombre de déplacement qui a la même apparence que l'élément View que vous transmettez en tant qu'argument, centrée sous l'endroit où l'utilisateur touche l'écran.

View.DragShadowBuilder()

Si vous utilisez ce constructeur, aucun objet View n'est disponible dans l'objet View.DragShadowBuilder. Le champ est défini sur null. Vous devez étendre View.DragShadowBuilder et remplacer ses méthodes, sinon vous obtiendrez une ombre de déplacement invisible. Le système ne génère pas d'erreur.

La classe View.DragShadowBuilder comporte deux méthodes qui créent ensemble l'ombre du déplacement:

onProvideShadowMetrics()

Le système appelle cette méthode immédiatement après avoir appelé startDragAndDrop(). Utilisez cette méthode pour envoyer les dimensions et le point de contact de l'ombre de déplacement au système. Cette méthode comporte deux paramètres:

outShadowSize:objet Point. La largeur de l'ombre de déplacement correspond à x, et sa hauteur à y.

outShadowTouchPoint:objet Point. Le point de contact est l'emplacement dans l'ombre du glissement qui doit se trouver sous le doigt de l'utilisateur pendant le déplacement. Sa position X correspond à x et sa position Y à y.

onDrawShadow()

Immédiatement après l'appel de onProvideShadowMetrics(), le système appelle onDrawShadow() pour créer l'ombre du déplacement. La méthode comporte un seul argument, un objet Canvas que le système construit à partir des paramètres que vous fournissez dans onProvideShadowMetrics(). La méthode dessine l'ombre du déplacement sur le Canvas fourni.

Pour améliorer les performances, réduisez la taille de l'ombre du déplacement. Pour un seul élément, vous pouvez utiliser une icône. Pour une sélection de plusieurs éléments, vous pouvez utiliser des icônes dans une pile plutôt que des images complètes réparties sur l'écran.

Faire glisser des écouteurs d'événements et des méthodes de rappel

Un View reçoit des événements de déplacement avec un écouteur d'événements de déplacement qui implémente View.OnDragListener ou avec la méthode de rappel onDragEvent() de la vue. Lorsque le système appelle la méthode ou l'écouteur, il fournit un argument DragEvent.

Dans la plupart des cas, il est préférable d'utiliser un écouteur plutôt que la méthode de rappel. Lorsque vous concevez des interfaces utilisateur, vous ne sous-classez généralement pas les classes View, mais l'utilisation de la méthode de rappel vous oblige à créer des sous-classes pour remplacer la méthode. En comparaison, vous pouvez implémenter une classe d'écouteur, puis l'utiliser avec plusieurs objets View différents. Vous pouvez également l'implémenter en tant que classe intégrée anonyme ou expression lambda. Pour définir l'écouteur pour un objet View, appelez setOnDragListener().

Vous pouvez également modifier l'implémentation par défaut de onDragEvent() sans remplacer la méthode. Définissez un OnReceiveContentListener sur une vue. Pour en savoir plus, consultez setOnReceiveContentListener(). La méthode onDragEvent() effectue ensuite les opérations suivantes par défaut:

  • Renvoie la valeur "true" en réponse à l'appel de startDragAndDrop().
  • Elle appelle performReceiveContent() si les données par glisser-déposer sont déposées sur la vue. Les données sont transmises à la méthode en tant qu'objet ContentInfo. La méthode appelle OnReceiveContentListener.

  • Renvoie la valeur "true" si les données de glisser-déposer sont déposées sur la vue et que OnReceiveContentListener consomme tout le contenu.

Définissez OnReceiveContentListener pour gérer les données spécifiquement pour votre application. Pour assurer la rétrocompatibilité jusqu'au niveau d'API 24, utilisez la version Jetpack de OnReceiveContentListener.

Vous pouvez utiliser un écouteur d'événements de déplacement et une méthode de rappel pour un objet View. Dans ce cas, le système appelle d'abord l'écouteur. Le système n'appelle pas la méthode de rappel, sauf si l'écouteur renvoie false.

La combinaison de la méthode onDragEvent() et de View.OnDragListener est analogue à celle des onTouchEvent() et View.OnTouchListener utilisés avec les événements tactiles.