ここ 1 週間ほど Flex 2 に戯れていたのでそのまとめ。こと UI 関連はド素人なのでもっと良い方法があるかも。
やりたいことは Active Dashboard とか Google のアレみたいにパネル? を掴んで場所を入れ替えしたいわけです。
まず Flex のドラッグ&ドロップのイベントハンドリングについて。 がわかりやすい記事だった。Panel とかのデフォルトのドラッグ&ドロップ操作が用意されてないコンポーネントは自前で処理を書いてやればいいらしい。livedocs の Adobe - Error Page も参考になる。
んでまぁ、ちと長いサンプルソース……ちと冗長な部分もあるけどそこまぁ見逃してくれ。ホントはココに swf 張ってソース添付したかったんだけど……
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="horizontal"> <mx:Script> <![CDATA[ import mx.core.Container; import mx.events.DragEvent; import mx.managers.DragManager; import mx.controls.TextInput; import mx.core.DragSource; public function mouseDownHandler(event:MouseEvent):void { var dragInitiator:Panel = event.currentTarget as Panel; if (dragInitiator.contentMouseY >= 0) return; var dragSource:DragSource = new DragSource(); dragSource.addData(dragInitiator, "dragInitiatorPanel"); var panelProxy:Panel = new Panel(); panelProxy.width=dragInitiator.width; panelProxy.height=dragInitiator.height; panelProxy.title=dragInitiator.title; var t:TextInput = new TextInput(); t.text = "コピー中now"; panelProxy.addChild(t); panelProxy.setStyle('backgroundColor', dragInitiator.getStyle('backgroundColor')); DragManager.doDrag(dragInitiator, dragSource, event, panelProxy); } public function dragEnterHandler(event:DragEvent):void { var dropTarget:Panel = event.currentTarget as Panel; DragManager.acceptDragDrop(dropTarget); } public function dragOverHandler(event:DragEvent):void { var dropTarget:Panel = event.currentTarget as Panel; dropTarget.setStyle("backgroundAlpha", "0.3"); dropTarget.setStyle("borderStyle", "solid"); } public function dragExitHandler(event:DragEvent):void { var dropTarget:Panel = event.currentTarget as Panel; dropTarget.setStyle("backgroundAlpha", "1.0"); dropTarget.setStyle("borderStyle", "default"); } public function dragDropHandler(event:DragEvent):void { var dropTarget:Panel = event.currentTarget as Panel; var parentContainer:Container = dropTarget.parent as Container; var dragInitiator:Panel = event.dragSource.dataForFormat("dragInitiatorPanel") as Panel; var dragX:uint = dragInitiator.x; var dragY:uint = dragInitiator.y; var dragW:uint = dragInitiator.width; var dragH:uint = dragInitiator.height; var dropX:uint = dropTarget.x; var dropY:uint = dropTarget.y; var dropW:uint = dropTarget.width; var dropH:uint = dropTarget.height; //dragInitiator.x = dropX; //dragInitiator.y = dropY; //dragInitiator.width = dropW; //dragInitiator.height = dropH; //dropTarget.x = dragX; //dropTarget.y = dragY; //dropTarget.width = dragW; //dropTarget.height = dragH; var indexDrag:uint = parentContainer.getChildIndex(dragInitiator); var indexDrop:uint = parentContainer.getChildIndex(dropTarget); parentContainer.setChildIndex(dragInitiator, indexDrop); parentContainer.setChildIndex(dropTarget, indexDrag); dropTarget.setStyle("backgroundAlpha", "1.0"); dropTarget.setStyle("borderStyle", "default"); } ]]> </mx:Script> <mx:Panel id="panel1" width="140" height="200" title="ぱねる1" mouseDown="mouseDownHandler(event)" dragEnter="dragEnterHandler(event)" dragOver="dragOverHandler(event)" dragExit="dragExitHandler(event)" dragDrop="dragDropHandler(event)" x="10" y="10"> </mx:Panel> <mx:Panel id="panel2" width="120" height="200" title="ぱねる2" mouseDown="mouseDownHandler(event)" dragEnter="dragEnterHandler(event)" dragOver="dragOverHandler(event)" dragExit="dragExitHandler(event)" dragDrop="dragDropHandler(event)" x="158" y="10"> </mx:Panel> <mx:Panel id="panel3" width="100" height="200" title="ぱねる3" mouseDown="mouseDownHandler(event)" dragEnter="dragEnterHandler(event)" dragOver="dragOverHandler(event)" dragExit="dragExitHandler(event)" dragDrop="dragDropHandler(event)" x="286" y="10"> </mx:Panel> </mx:Application>
キモとなるっぽいところのメモ。
まずは mouseDownHandler から。下記の if はタイトルバーだけ掴んでドラッグ&ドロップさせるためのもの。Panelの移動 にあるように、なんらかの措置しないと Panel 全体でドラッグ&ドロップ拾ってしまうので。
var dragInitiator:Panel = event.currentTarget as Panel; if (dragInitiator.contentMouseY >= 0) return;
次に、下記コードでドラッグ&ドロップ中に表示するプロキシーを生成する。ドラッグ元 Panel のコピー作るイメージだろうか。頑張って Panel ん中に表示してるコンポーネントのコピーも作ればクールなドラッグ&ドロップが作れそう。
var panelProxy:Panel = new Panel(); panelProxy.width=dragInitiator.width; ... DragManager.doDrag(dragInitiator, dragSource, event, panelProxy);
dragDropHandler の下記コードで Panel の位置入れ替えを行う。……ってか一瞬とはいえ、異なるインデックスが同じコンポーネント参照しちゃうんだけど、Flex 的にはおkなのかなぁ。
parentContainer.setChildIndex(dragInitiator, indexDrop); parentContainer.setChildIndex(dropTarget, indexDrag);
メソッドのネーミング的にイケそうな気がしたんだけど↓はダメ。childIndex の順序入れ替えしてあげないとダメみたいだね。
parentContainer.swapChildrenAt(indexDrag, indexDrop);
が、親コンポーネントのレイアウトが absolute だと childIndex の入れ替えではダメ。コメントアウトした x,y,width,height の入れ替えはそのためのコード。たぶんだけど Java の Swing のレイアウトマネージャみたく、コンポーネントが追加されたインデックス順でレイアウトマネージャが動的に描画するんだろう。だけど絶対座標配置の場合はそうでなくなる、と。まぁそんな感じだろう。