Adobe AIR の Drag&Drop処理に関する考察
ActionScript3.0において、SpriteをあるContainer内で、ドラッグ処理を使って自由に移動させたい場合
spriteInstance.startDrag();
spriteInstance.stopDrag();
で、移動開始、ドラッグ処理、移動終了を簡単に記述することが出来ます。
更にここに、別のContainerへのDrag&Drop(D&D)処理を行う場合、
DragManager.doDrag(arg..)
を利用することによって、簡単にD&D処理を記述することが可能です。おそらく、ここまでは皆さんご存知だと思います。ここからが問題です。
Adobe AIRのDrag&Dropは、FlexのDrag&Dropと異なります。どう違うかと言うと、
がそれぞれ、DragManagerが利用するSingletonとして与えられます。ここで厄介なのがNativeDragManagerImpl.doDrag(args..)のD&D処理とstartDrag()のドラッグ移動処理とが競合して、startDrag()によるドラッグ移動処理を後回しにするということです。イメージ的には、D&D処理終了後 → D&D処理終了地点のマウス位置にSpriteが移動する感じです。
もう少し細かい話をすると、AIRの場合でも、利用するクラスによって、それぞれのImplのDragManagerへの割り当てが異なります。具体的に言うと次の通りです。
mx:Application → DragManagerImpl
mx:WindowedApplication → NativeDragManagerImpl
つまり、mx:Applicationを利用した場合、ドラッグ移動処理とD&D処理は競合しないのですが、mx:WindowedApplicationを利用している場合は競合してしまいます。私は諸事情からmx:WindowedApplicationを使わなければならないので、次の様にして競合を回避しています。
//これだと内部では、NativeDragManagerImplが使用される
DragManager.doDrag(args...)//明示的にDragManagerImplを呼び出す。
DragManagerImpl.getInstance().doDrag(args...)
このように、Implを明示的に呼び出すことで、ドラッグ移動処理とD&D処理との競合を回避出来ます。但し、この方式でやった場合、DragManagerImpl.getInstance().endDrag()が自動では呼び出されなくなります。そのためDragEvent.DRAG_COMPLETEなどのイベントリスナを利用して、DragManagerImpl.getInstance().endDrag()も明示的に呼び出す必要があります。
ちなみに、mx:Applicationを利用していて、NativeDragManagerImplを利用したい場合は、逆をやればOKです。
参考:http://livedocs.adobe.com/flex/3_jp/html/help.html?content=dragdrop_6.html