每天逛逛TWaver論壇已經(jīng)成為一種習(xí)慣,今天看到一個(gè)非常有意思的帖子:
http://twaver.servasoft.com/forum/viewtopic.php?f=14&t=3129
當(dāng)兩個(gè)Group重疊時(shí),Group中的Node會(huì)始終顯示在兩個(gè)Group之上,呈現(xiàn)結(jié)果如下圖(引用了帖子中的圖片):
這簡(jiǎn)直是無(wú)法忍受的,如果把這樣的呈現(xiàn)效果拿給客戶看,不被罵死才怪。我們要的是這種效果(引用了帖子中的圖片):
帖子中給出的解決方案是:為每個(gè)Group生成一個(gè)layer,當(dāng)選中Group中,將對(duì)應(yīng)的layer置頂。想法很美好,現(xiàn)實(shí)卻很殘酷:帖子最后給出的代碼雖然可以部分實(shí)現(xiàn)這種效果,但是在我看來(lái)仍然不夠完美,甚至說(shuō)有瑕疵。大家可以把代碼copy下來(lái),然后運(yùn)行測(cè)試:先將所有的Group展開(kāi),然后點(diǎn)擊group1,再點(diǎn)擊group2_2并拖動(dòng)與group1重合,你看到了什么?
group2_2雖然被置頂,但是它的parent:group2卻仍然被group1和group1_1遮擋了。這是因?yàn)樘又械慕鉀Q方案只是處理了當(dāng)前點(diǎn)擊Group自身和的child Group(將child Group置頂),卻沒(méi)有處理parent Group,所以group2_2的parent:group2仍然顯示在后面。下圖是測(cè)試的結(jié)果(group1是group1_1的parent;group2是group2_2的parent;group1和group2是平級(jí),同是group_root1的children):
可以很明顯地看到,group2_2確實(shí)被置頂了,但是group2卻仍然被遮擋,理想的狀況下,當(dāng)我們點(diǎn)擊group2_2的時(shí)候,group2應(yīng)該緊緊跟隨在group2_2下面,并遮擋group1和group1_1,效果如下圖:
這樣就好看多了,當(dāng)我們拖動(dòng)group2_2的時(shí)候,group2應(yīng)該僅僅跟隨在group2_2下邊,并且遮擋住group1和group1_1。
我把帖子中的代碼改造了一下,最終實(shí)現(xiàn)了這種效果,獨(dú)樂(lè)樂(lè)不如眾樂(lè)樂(lè),下面我把我的實(shí)現(xiàn)代碼貼到此博客上與大家分享,如果有錯(cuò)誤或可以優(yōu)化的地方希望大家可以批評(píng)指正,感激不盡!
我們?nèi)匀谎赜锰又械脑O(shè)計(jì)思路:為每個(gè)Group生成一個(gè)layer,點(diǎn)擊Group時(shí)將layer置頂,但是我們還要考慮Group的parent Group和child Group:將child Group置頂,parent Group緊隨其后。
首先Group可以嵌套多層,而且我們也不確定可能會(huì)嵌套幾層,所以遞歸是不可避免的了。對(duì)于這種比較復(fù)雜的算法,直觀的代碼遠(yuǎn)遠(yuǎn)要比語(yǔ)言描述有力的多,直接貼上代碼:
1 private function init():void {
2 this.initBox();
3 network.elementBox = box;
4 network.addInteractionListener(function(e:InteractionEvent):void {
5 if(e.kind == InteractionEvent.CLICK_ELEMENT){
6 var g:Group = null;
7 if(e.element is Group){
8 g = Group(e.element);
9 }else if(e.element.parent is Group){
10 g = Group(e.element.parent);
11 }
12
13 var ele:Element=e.element as Element;
14 var rootGroup:Group=g;
15 var parentArr:ArrayCollection=new ArrayCollection;
16 parentArr.addItem(g);
17 while(ele.parent){
18 if(ele.parent is Group){
19 rootGroup=ele.parent as Group;
20 parentArr.addItem(rootGroup);
21 }
22 ele=ele.parent as Element;
23 }
24 iterator(rootGroup,parentArr);
25 }
26 });
27 }
28 private function iterator(parentGroup:Group,parentArr:ArrayCollection):void{
29 var nextParentGroup:Group=null;
30 var layer:Layer = box.layerBox.getLayerByID(parentGroup.id) as Layer;
31 if(layer){
32 box.layerBox.moveToBottom(layer);
33 }
34 for(var i=0;i<parentGroup.children.count;i++){
35 var ele:Element=parentGroup.getChildAt(i) as Element;
36 if(ele is Group){
37 var g:Group=Group(ele);
38 if(parentArr.contains(g)){
39 nextParentGroup=g;
40 continue;
41 }
42 var layer:Layer = box.layerBox.getLayerByID(g.id) as Layer;
43 if(layer){
44 box.layerBox.moveToBottom(layer);
45 }
46 iterator(Group(ele),parentArr);
47 }
48 }
49 if(nextParentGroup)
50 iterator(nextParentGroup,parentArr);
51 }
盡管語(yǔ)言乏力,但是為了方便大家理解,我還是盡力描述一下:
當(dāng)我點(diǎn)擊一個(gè)Group的時(shí)候,獲取這個(gè)Group的根Group,稱之為rootGroup,將rootGroup傳入iterator方法遞歸遍歷,把所有的Group置頂一遍,但是越是靠后置頂?shù)模驮娇壳帮@示。所以為了讓我們點(diǎn)擊的Group能夠靠前顯示,我們需要先遍歷無(wú)關(guān)Group(例子中的group1和group1_1),最后再遍歷group2和group2_2(其中g(shù)roup2_2要最后遍歷)。這個(gè)遍歷先后順序怎么控制呢,通過(guò)這段代碼來(lái)控制:
1 if(parentArr.contains(g)){
2 nextParentGroup=g;
3 continue;
4 }
parentArr集合里包含了我們點(diǎn)擊的Group的所有的parent Group,我們判斷如果當(dāng)前遍歷到的group在parentArr集合中,就跳過(guò)循環(huán),直到for結(jié)束后再遍歷它。
這是大致的思路,我覺(jué)得這些描述+代碼應(yīng)該可以讓大家理解,不知道這樣頻繁的置頂對(duì)效率有沒(méi)有影響,希望大家能提出優(yōu)化方案。最后附上完整的代碼
見(jiàn)原文最下方