本例是Flex3 Cookbook 3.27节的内容,需求是要让用户可以在Tile 容器里面拖拽其瓷砖(tile)并且在用户放下瓷砖(tile)的时候容器重组。
书中示例代码如下:
<mx:Tile xmlns:mx="http://www.adobe.com/2006/mxml" width="300" height="600" direction="horizontal"> <mx:Script> <![CDATA[ import mx.core.UIComponent; private function childStartDrag(event:Event):void { (event.currentTarget as UIComponent).startDrag(false, this.getBounds(stage)); (event.currentTarget as UIComponent).addEventListener(MouseEvent.MOUSE_UP, childStopDrag); (event.currentTarget as UIComponent).addEventListener(MouseEvent.ROLL_OUT, childStopDrag); swapChildren((event.currentTarget as UIComponent), getChildAt(numChildren-1)); } private function childStopDrag(event:Event):void { swapChildren((event.currentTarget as UIComponent), hitTestChild((event.currentTarget as UIComponent))); (event.currentTarget as UIComponent).stopDrag(); this.invalidateDisplayList(); this.invalidateProperties(); } private function hitTestChild(obj:UIComponent):DisplayObject { for(var i:int = 0; i<this.numChildren; i++) { if(this.getChildAt(i).hitTestObject(obj)) { return getChildAt(i); } }r return getChildAt(0) } ]]> </mx:Script> <mx:Panel title="First Panel" mouseDown="childStartDrag(event)"> <mx:Text text="First Text"/> </mx:Panel> <mx:Panel title="Second Panel" mouseDown="childStartDrag(event)"> <mx:Text text="Second Text"/> </mx:Panel> <mx:Panel title="Third Panel" mouseDown="childStartDrag(event)"> <mx:Text text="Third Text"/> </mx:Panel> <mx:Panel title="Fourth Panel" mouseDown="childStartDrag(event)"> <mx:Text text="Fourth Text"/> </mx:Panel> </mx:Tile>
?
?
本着学习Flex4的原则,将本书中的例子用Flex4控件加以改造,但是运行起来各种问题(事实上,书中的代码在Flex3中运行也是各种问题),最主要是swapChildren方法在Flex4中对应的swapElements方法执行后会自动替换两个控件的位置,导致无法拖拽,若不调用该方法,则顺序靠前的控件在拖拽的过程中会与顺序靠后的控件重叠一部分,导致无法拖放,于是乎开始改造。
使用拖拽代理,可解决控件重叠的问题。本来是想另拖拽源控件隐藏,但是在拖拽失败时候无法重新显示出来,因此暂不考虑。
代码如下:
<?xml version="1.0" encoding="utf-8"?> <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600"> <s:layout> <s:BasicLayout/> </s:layout> <fx:Script> <![CDATA[ import mx.core.BitmapAsset; import mx.core.DragSource; import mx.core.UIComponent; import mx.events.DragEvent; import mx.events.FlexEvent; import mx.managers.DragManager; private var targetElem:UIComponent; private function childStartDrag(event:MouseEvent):void { var ui:UIComponent = event.currentTarget as UIComponent; var proxyBox:BitmapAsset = new BitmapAsset(); proxyBox.bitmapData = new BitmapData(ui.width, ui.height); proxyBox.bitmapData.draw(ui); var ds:DragSource = new DragSource(); ds.addData(ui, "border"); DragManager.doDrag(ui, ds, event, proxyBox); } protected function tg_dragEnterHandler(event:DragEvent):void { if (event.dragSource.hasFormat("border")) { DragManager.acceptDragDrop(event.currentTarget as UIComponent); } } protected function tg_dragDropHandler(event:DragEvent):void { var elem:UIComponent = event.dragInitiator as UIComponent; if (targetElem && targetElem != elem) { tg.swapElements(targetElem, elem); } } protected function tg_creationCompleteHandler(event:FlexEvent):void { for (var i:int = 0; i < tg.numElements; i++) { tg.getElementAt(i).addEventListener(DragEvent.DRAG_ENTER, elemDragEnter, false, 0, true); tg.getElementAt(i).addEventListener(MouseEvent.MOUSE_DOWN, childStartDrag, false, 0, true); } } protected function elemDragEnter(event:DragEvent):void { if (targetElem != event.currentTarget) { targetElem = event.currentTarget as UIComponent; } } ]]> </fx:Script> <fx:Declarations> <!-- 将非可视元素(例如服务、值对象)放在此处 --> </fx:Declarations> <s:TileGroup id="tg" dragEnter="tg_dragEnterHandler(event)" dragDrop="tg_dragDropHandler(event)" creationComplete="tg_creationCompleteHandler(event)" x="129" y="58"> <s:BorderContainer> <s:Label text="First Text"/> </s:BorderContainer> <s:BorderContainer> <s:Label text="Second Text"/> </s:BorderContainer> <s:BorderContainer> <s:Label text="Third Text"/> </s:BorderContainer> <s:BorderContainer> <s:Label text="Fourth Text"/> </s:BorderContainer> </s:TileGroup> </s:Application>
?