Utiliser le DragManager de Flex ( 1ère partie )
Les composants d’affichage de listes ( List, DataGrid, TileList … ) intègrent un mécanisme de drag’n'Drop natif très simple à utiliser.
La classe DragManager permet quant à elle de définir des comportements de drag’n'drop avec n’importe quel composant graphique Flex.
Certains composants propose des propriétés dragEnabled ou dropEnabled permettant de gérer les transferts depuis et vers eux :
<dataGrid dragEnabled= "true" dragMoveEnabled = "true" dropEnabled="true" />
La classe DragManager va nous permettre de créer notre propre mécanisme de glisser / déposer. Voyons un exemple d’utilisation de cette classe à travers la création d’un jeu de “mot dans le désordre”.
Fonctionnement
Une opération de “glisser / déposer” se fait en 3 étapes :
1. le clic sur l’élément à déplacer
2. Le déplacement de l’élément
3. Le dépot de l’élément
La classe DragManager va nous permettre de gérer :
- la copie et le transfert des données
- la création d’une “image proxy” ( représentant l’objet pendant le déplacement )
- la vérification des droits de dépôt de l’élément
Durant les trois étapes, nous aurons à écouter les événements de la classe DragEvent émis à la fois par le composant déplacé et par les “composants cibles potentiels” ( les composants survolés ).
Nous utiliserons également :
- les méthodes statiques de la classe DragManager pour initier le déplacement ( doDrag( … ) ) et vérifier le droit de dépot ( acceptDragDrop(…) )
- un objet DragSource pour transférer les données.
1. Le déplacement
1.1 Capter l’évenement mouseDown
Pour permettre le déplacement d’un composant graphique Flex,, il faut créer un écouteur d’événement MouseEvent.MOUSE_DOWN sur les objets pouvant être déplacés :
<mx:Label id="l"
fontSize="32" text="{rpSrc.currentItem.lettre}"
horizontalCenter="0" verticalCenter="0"
mouseDown="drag( event )"
/>
1.2 Stocker les données déplacées et initier le déplacement
A chaque émission de cet événement, nous allons:
- créer une instance de DragSource et y rajouter les données à déplacer
- appeler la méthode statique DragManager.doDrag(…) pour initier le déplacement
private function drag( e:MouseEvent):void
{
var dgData:DragSource = new DragSource();
var dgText:String = (e.target.parent as Label).text ;
dgData.addData( dgText , "lettre" );
dgData.addData( getLetterPosition(dgText) , "position" );
DragManager.doDrag( UIComponent(e.target.parent) , dgData, e );
}
Pour stocker les données dans l’objet DragSource, on peut utiliser la méthode addData( donnée:Object , nomPropriété:String )
Les données peuvent être utilisées pour vérifier les “droits de dépots” sur un composant cible.
La méthode doDrag( … ) du composant DragManager nécessite quant à elle plusieurs paramètres :
- le dragInitiator : IUIComponent ( obligatoire ) : le composant ayant initié le déplacement, généralement l’objet déplacé
- la dragSource : DragSource ( obligatoire ) : instance de DragSource contenant les données devant être déplacées
- le mouseEvent : MouseEvent ( obligatoire ) : événement à l’origine du déplacement ( MouseEvent.MOUSE_DOWN )
- la dragImage : IFlexDisplayObject ( optionnel / default = null ) : “Image proxy” utilisée pour représenter le composant déplacé durant le déplacement. Si aucune image n’est défini, un rectangle gris est dessiné par défaut.
- le xOffSet : Number ( optionnel / default = 0) : position horizontale de l’image proxy par rapport au curseur.
- le yOffSet : Number ( optionnel / default = 0 ) : position verticale de l’image proxy par rapport au curseur
- l’ imageAlpha : Number ( optionnel / default = 0.5 ) : opacité de l’image proxy
- allowMove : Boolean ( optionnel / defaut = true ) : les données peuvent être transférées ( couper / glisser / coller ) sur un objet cible.
Le composant n’est pas lui réellement déplacé avant le drop. DragManager crée une dragImage qui représente le composant déplacé. Une fois le dépôt effectué, si il est autorisé par le composant cible, les données peuvent être transférées de “l’objet source” à “l’objet cible”.
2. Survol des cibles
Lorsque le composant déplacé survole des composants potentiellement “cibles”, ces derniers émettent des événements DragEvent.DRAG_ENTER.
<local:DropableCanvas width="60" height="80" dragEnter="isDropable(event)" >
Nous allons pouvoir écouter ces événements afin de tester si l’objet peut être déposé sur l’objet survolé.
Le plus simple est de vérifier si le dragSource contenu dans le DragEvent.DRAG_ENTER contient certaines propriétés.
A chaque dragEnter, la méthode isDropable() est appelée.
Si la/les proprieté(s) recherchée(s) sont bien présente(s) dans le dragSource , on peut appeler la méthode DragManager.acceptDragDrop( target : IUIComponent ) où target est le composant pouvant accepter le dépot des données.
private function isDropable( e:DragEvent ):void
{
var dgData:DragSource = e.dragSource ;
// référence du champ texte du Canvas Cible
var cibleText:Label = Container(e.target).getChildAt(0) as Label ;
// si le champ cible est différent du champ source et que le champ cible est vide : autoriser le drop
if ( e.dragInitiator != cibleText && cibleText.text == "" )
if ( dgData.hasFormat("lettre") && dgData.hasFormat("position") )
DragManager.acceptDragDrop( UIComponent( e.target ) );
}
Si ce n’est pas le cas, l’objet déplacé sera signalé comme “non autorisé” à être déposé dans le composant cible courant ( curseur “interdit” ).
3. Dépot des données
Pour capter le dépot, on peut écouter :
- l’événement DragEvent.dragDrop sur l’objet “cible”.
<local:DropableCanvas width="60" height="80"
backgroundColor="#EFEFEF" borderColor="#CCCCCC" borderStyle="solid"
dragEnter="isDropable(event)"
dropData="{lettres[rpCibles.currentIndex]}"
dragDrop="addLettre( event )"
>
La méthode addLettre() est ici appelée lors d’un DragEvent.dragDrop. Cette méthode va nous permettre d’effectuer le transfert de données ( ici la lettre et sa position ).
private function addLettre( e:DragEvent ):void
{
// récupération des données
var dropLetter:String = String( e.dragSource.dataForFormat("lettre") );
var dropPosition:uint = uint( e.dragSource.dataForFormat("position") );
// référence du champ texte du Canvas Cible
var cibleText:Label = Container(e.target).getChildAt(0) as Label ;
// remplit le champ texte cible
cibleText.text = dropLetter ;
// si la lettre est déposé dans un Canvas cible : test si elle est déposé à la bonne position
if ( e.target is DropableCanvas )
if ( DropableCanvas(e.target).dropData.position == dropPosition )
cibleText.setStyle( "color" , 0x00FF00 );
}
Dans cet exemple, j’ai ajouté un classe DropableCanvas. Cette classe possède un propriété publique dropData, qui permet de stocker les réponses correctes de chaque “composant de dépôt”. Au moment du drop, cela nous permet de tester si la lettre est bien posée au bon endroit.
- l’évenement DragEvent.dragComplete sur le composant “émetteur”.
Lorsque les données sont “lachées”, et quelque soit le résultat du drag’n'drop, l’objet émetteur émet un dragComplete.
<mx:Label id="cibleLabel" fontSize="32" horizontalCenter="0" verticalCenter="0" mouseDown="drag( event )" dragComplete="onDragComplete( event )" />
Grâce à la propriété action de l’événement nous pouvons savoir le résultat du drop. ( move, link, none ou copy )
private function onDragComplete( e:DragEvent ):void
{
if ( e.action == DragManager.MOVE )
Label( e.target ).text = "";
}
Dans un prochain tutoriel nous verrons comment personnaliser graphiquement cette opération.
Tags: Flex, interactivité, Tutoriels


--> 24 décembre 2008 ( 14:33 )
Je vous ai rencontré, tous les 3, le premier jour de l’Adobe MAX…
Sinon, j’aime bien ce type de post, qui illustre par l’exemple, la mise en oeuvre du Drag&Drop. Le DnD est immédiat pour les composants à base de List, mais c’est plus complexe quand il s’agit d’utiliser le DragManager.
Donc j’attends la deuxième partie!
Xebia avait proposé un post http://blog.xebia.fr/2008/06/19/drag-and-drop-flex/, qui présente rapidement comment utiliser le DragManager pour déplacer une image.
En complément, j’ai rédigé un billet qui met l’accent sur DnD d’image. Il montre aussi comment positionner l’image proxy du DragManager avec une copie de l’image qu’on est en train de déplacer. Avec un petit complément pour le drop, histoire que l’image reste à l’endroit du relachement de la souris…
http://flex.scoutant.org/post/2008/10/No-Move-API-for-Flex-Falling-back-Drag-Drop-API