Tile 容器内部拖拽

本例是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>

相关推荐