How to implement custom drag functionality in a Flex list control

apache-flex

Flex has built in drag-n-drop for list controls, and allows you to override this. But they don't cover this in examples. The built-in functionality automatically drags the list-item, if you want to override this you find the handlers are being set up on the list itself.
What I specifically want to do, is my TileList shows small thumbnails of items I can drag onto a large Canvas. As I drag an item from the list, the drag proxy should be a different image.

So, I followed the technique suggested and it only works if I explicitly set the width/height on the proxy Image. Why?

Best Answer

It's not obvious until you've tried it =) I struggled with the same thing just a few weeks ago. This was my solution:

The list:

<List>
  <mouseDown>onListMouseDown(event)</mouseDown>
</Tree>

The mouse down handler:

private function onMouseDown( event : MouseEvent ) : void {
  var list : List = List(event.currentTarget);

  // the data of the clicked row, change the name of the class to your own
  var item : MyDataType = MyDataType(list.selectedItem);

  var source : DragSource = new DragSource();

  // MyAwsomeDragFormat is the key that you will retrieve the data by in the
  // component that handles the drop
  source.addData(item, "MyAwsomeDragFormat");

  // this is the component that will be shown as the drag proxy image
  var dragView : UIComponent = new Image();

  // set the source of the image to a bigger version here
  dragView.source = getABiggerImage(item);

  // get hold of the renderer of the clicked row, to use as the drag initiator
  var rowRenderer : UIComponent = UIComponent(list.indexToItemRenderer(list.selectedIndex));

  DragManager.doDrag(
    rowRenderer,
    source,
    event,
    dragView
  );
}

That will start the drag when the user clicks an item in the list. Notice that I don't set dragEnabled and the other drag-related properties on the list since I handle all that myself.

It can be useful to add this to the beginning of the event handler:

if ( event.target is ScrollThumb || event.target is Button ) {
  return;
}

Just to short circuit if the user clicks somewhere in the scrollbar. It's not very elegant but it does the job.

Related Topic