利用Layer优化Group显示

每天逛逛TWaver论坛已经成为一种习惯,今天看到一个非常有意思的帖子:http://twaver.servasoft.com/forum/viewtopic.php?f=14&t=3129

当两个Group重叠时,Group中的Node会始终显示在两个Group之上,呈现结果如下图(引用了帖子中的图片):

利用Layer优化Group显示

这简直是无法忍受的,如果把这样的呈现效果拿给客户看,不被骂死才怪。我们要的是这种效果(引用了帖子中的图片):

利用Layer优化Group显示

帖子中给出的解决方案是:为每个Group生成一个layer,当选中Group中,将对应的layer置顶。想法很美好,现实却很残酷:帖子最后给出的代码虽然可以部分实现这种效果,但是在我看来仍然不够完美,甚至说有瑕疵。大家可以把代码copy下来,然后运行测试:先将所有的Group展开,然后点击group1,再点击group2_2并拖动与group1重合,你看到了什么?

group2_2虽然被置顶,但是它的parent:group2却仍然被group1和group1_1遮挡了。这是因为帖子中的解决方案只是处理了当前点击Group自身和的child Group(将child Group置顶),却没有处理parent Group,所以group2_2的parent:group2仍然显示在后面。下图是测试的结果(group1是group1_1的parent;group2是group2_2的parent;group1和group2是平级,同是group_root1的children):

利用Layer优化Group显示

可以很明显地看到,group2_2确实被置顶了,但是group2却仍然被遮挡,理想的状况下,当我们点击group2_2的时候,group2应该紧紧跟随在group2_2下面,并遮挡group1和group1_1,效果如下图:

利用Layer优化Group显示

这样就好看多了,当我们拖动group2_2的时候,group2应该仅仅跟随在group2_2下边,并且遮挡住group1和group1_1。

我把帖子中的代码改造了一下,最终实现了这种效果,独乐乐不如众乐乐,下面我把我的实现代码贴到此博客上与大家分享,如果有错误或可以优化的地方希望大家可以批评指正,感激不尽!

我们仍然沿用帖子中的设计思路:为每个Group生成一个layer,点击Group时将layer置顶,但是我们还要考虑Group的parent Group和child Group:将child Group置顶,parent Group紧随其后。首先Group可以嵌套多层,而且我们也不确定可能会嵌套几层,所以递归是不可避免的了。对于这种比较复杂的算法,直观的代码远远要比语言描述有力的多,直接贴上代码:

private function init():void {
				this.initBox();
				network.elementBox = box;
				network.addInteractionListener(function(e:InteractionEvent):void {
					if(e.kind == InteractionEvent.CLICK_ELEMENT){
						var g:Group = null;
						if(e.element is Group){
							g = Group(e.element);
						}else if(e.element.parent is Group){
							g = Group(e.element.parent);
						}

						var ele:Element=e.element as Element;
						var rootGroup:Group=g;
						var parentArr:ArrayCollection=new ArrayCollection;
						parentArr.addItem(g);
						while(ele.parent){
							if(ele.parent is Group){
								rootGroup=ele.parent as Group;
								parentArr.addItem(rootGroup);
							}
							ele=ele.parent as Element;
						}
						iterator(rootGroup,parentArr);
					}
				});
			}
private function iterator(parentGroup:Group,parentArr:ArrayCollection):void{
				var nextParentGroup:Group=null;
				var layer:Layer = box.layerBox.getLayerByID(parentGroup.id) as Layer;
				if(layer){
					box.layerBox.moveToBottom(layer);
				}
				for(var i=0;i<parentGroup.children.count;i++){
					var ele:Element=parentGroup.getChildAt(i) as Element;
					if(ele is Group){
						var g:Group=Group(ele);
						if(parentArr.contains(g)){
							nextParentGroup=g;
							continue;
						}
						var layer:Layer = box.layerBox.getLayerByID(g.id) as Layer;
						if(layer){
							box.layerBox.moveToBottom(layer);
						}
						iterator(Group(ele),parentArr);
					}
				}
				if(nextParentGroup)
					iterator(nextParentGroup,parentArr);
			}

尽管语言乏力,但是为了方便大家理解,我还是尽力描述一下:

当我点击一个Group的时候,获取这个Group的根Group,称之为rootGroup,将rootGroup传入iterator方法递归遍历,把所有的Group置顶一遍,但是越是靠后置顶的,就越靠前显示。所以为了让我们点击的Group能够靠前显示,我们需要先遍历无关Group(例子中的group1和group1_1),最后再遍历group2和group2_2(其中group2_2要最后遍历)。这个遍历先后顺序怎么控制呢,通过这段代码来控制:

if(parentArr.contains(g)){
	nextParentGroup=g;
	continue;
}

parentArr集合里包含了我们点击的Group的所有的parent Group,我们判断如果当前遍历到的group在parentArr集合中,就跳过循环,直到for结束后再遍历它。这是大致的思路,我觉得这些描述+代码应该可以让大家理解,不知道这样频繁的置顶对效率有没有影响,希望大家能提出优化方案。最后附上完整的代码demo(见原文最下方)

你可能感兴趣的:(group)