近期开始学Flex,准备做一个用于左右拖拉的例子出来,具体就是将一个树(或者是List)中的结点拖到右边的一个树上去.这种例子网上已经有很多了,而且很多都是可以运行的.
这里讲的主要是将一个结点拖到一个树干,而不是随便拖过去的例子.即右边有一个二级的树,第一级称之为parent结点,第二级称之为child结点,我们要做的例子就是将左边的tree(或者是list,其实就是一个list,这里用tree来代替)上的结点,拖到右边的parent结点上,而不是child结点上.
网上的很多教程都有讲怎么将其拖到右边去,却没有将拖到指定的结点上,最终出来的效果就是结点被随便的放到右边,而不是按照一定逻辑地放在指定parent结点下,成为这个parent结点的一个child结点.
开始进行,将定义两个tree结点,然后设置dataProvider,接下来,按照教程上的设置右边tree的dragEnter,dragOver,dragDrop等自定义函数.分别如下所示:
dragEnter:
private function enter(event:DragEvent):void { //追加可接受的 DragManager.acceptDragDrop(UIComponent(event.currentTarget)); }
dragOver:
event.preventDefault(); var tree:Tree = event.currentTarget as Tree; var dropIndex:int = tree.calculateDropIndex(event); tree.selectedIndex = dropIndex; var node:XML = tree.selectedItem as XML; if(node.@parent == 'true') { //设置成这个,可以进行移动操作 DragManager.showFeedback(DragManager.MOVE); } else { //设置成不可操作,不能进行以后的操作 DragManager.showFeedback(DragManager.NONE); }
这个没说的,其实就是对拖到哪个结点上作判断,如果是parent结点,则返回一个move操作,否则就返回一个none操作.通过查看tree的源代码,当这个showFeedBack为none时,结点将不会添加至右边去,最终会回退到原来的地方去.而move或者copy等就会执行相应的dragDrop事件了.
dragDrop:
private function drop(event:DragEvent):void { event.preventDefault(); var tree:Tree = event.currentTarget as Tree; var ds:DragSource = event.dragSource; var nodes:Array = ds.dataForFormat("treeItems") as Array; var dropIndex:int = tree.calculateDropIndex(event); tree.selectedIndex = dropIndex; var selected:XML = tree.selectedItem as XML; //右边添加结点 if(selected.@parent == "true") { for each(var i:XML in nodes ) { //删除原来的 xTree.dataDescriptor.removeChildAt(i.parent(), i,i.childIndex(),xTree.dataProvider); //再添加新的 tree.dataDescriptor.addChildAt(selected, i, 0); } } tree.selectedIndex = -1; }上面代码中tree表示右边的树,xTree表示左边的树. 在Tree中,有个函数必须调用,就是tree.calculateDropIndex,这个函数实际上会执行updateDropData操作,即处理哪个即将要drop到的是哪个item(即哪个结点),感觉很bt的.实际上在dragOver时就可以确定将要拖到哪个结点上去,这里不用简单的用tree.selectedItem来获取右边拖到哪个结点上了,必须用calculateDropIndex来确定信息.
第二个需要注意的就是从ds中取到的数据实际上是一个array,而不是我原来想的xmlList,如果这里写成as XMLList,则会返回一个null,从而下面处理就会出问题了.
接下来就准备将数据放到右边去了,而左边的数据则被删掉.值得注意的就是,在现有的tree的源代码中,最终的drop和remove操作,并不是在dragDrop中完成的,而是在dragComplete操作中完成的.就是说,在这里,它不会将数据最终drop下来,而是要等到dragComplete去了.官方的原话如下:
// If not dropping onto ourselves, then add the // items here if it's a copy operation. // If it's a move operation (and not on ourselves), then they // are added in dragCompleteHandler and are removed from // the source's dragCompleteHandler. We do both in dragCompleteHandler // because in order to be re-parented, they must be removed from their // original source FIRST. This means our code isn't coupled fantastically // as dragCompleteHandler must get the destination tree and // cast it to a Tree.
意思就是说,如果是move操作,那么这个操作最终将由源端进行处理,即这个complete操作是由左边的tree来完成的,而不是由右边的tree来完成......这样就有个问题,如果在dragDrop函数中由于某个问题,这个函数执行出错了,dragComplete会照常进行,而将结点移到右边去.
而且这也造成了,必须在源端上写一个dragComplete函数,我原来想的是在complete函数中将结点从左边移去,结果实现不了,在tree中complete函数中,删除source端结点用了以下三条语句:
parent = getParentItem(items[i]); index = getChildIndexInParent(parent, items[i]); removeChildItem(parent, items[i], index);其中,第二个函数是private,并且里面同时调用了其他private 属性,想override都不行.就只有在dragDrop下考虑了,所以最终的结果,由上代码所示,在dragDrop中将source结点删除,再往destination端写设置结点.
最好还是在source端,加上dragComplte函数,里面将默认的处理禁用掉,如下所示:
private function complete(event:DragEvent):void { //让默认的不起作用 event.preventDefault(); }
这样,就达到了将数据从左边移到右边.并且基于这种应用,将demo与服务器端通信连接起来,就可以进行实际应用的开发了:)
这是自己在网上参照了很多例子,没有写出左右指定拖动的情况下,乱打乱撞下,成功的代码.在此作一个标记,如果有人碰到与我相同的问题,也可以找到答案了:)