AS3:如何接触儿童的孩子?

时间:2017-03-31 21:20:23

标签: actionscript-3 flash parent-child children

是否有更好(更快,更短或更整洁)的方式来访问3层或更深的儿童精灵(物体)?如果孩子们都被给了名字,你知道这些名字。有没有比我下面的代码更好的方法呢?

var mySprite:DisplayObjectContainer = layerASprite.getChildByName(" layerA ")作为DisplayObjectContainer;

mySprite = mySprite.getChildByName(" layerB ")作为DisplayObjectContainer;

mySprite.getChildByName(" layerC ")。y = 200;

2 个答案:

答案 0 :(得分:3)

如果它们是唯一的,您可以以静态类变量/方法的形式创建“全局”注册表:

package
{
    public class Registry
    {
        static private var hash:Object = new Object;

        static public function register(name:String, target:DisplayObject):void
        {
            hash[name] = target;
        }

        static public function access(name:String):DisplayObject
        {
            return hash[name];
        }
    }
}

用法:

// Any MovieClip, frame 1 or class constructor.
import Registry;

Registry.register("deepChild", this);

// From any other place.
import Registry;

Registry.access("deepChild").y = 200;

或者,您可以使用通过单个字符串参数挖掘子项的子项的方法:

function offSpring(path:String):DisplayObject
{
    var aSplit:Array = path.split(".");
    var result:DisplayObject = this;

    while (aSplit.length)
    {
        var aParent:DisplayObjectContainer = result as DisplayObjectContainer;

        if (!aParent) return null;

        result = aParent.getChildByName(aSplit.shift());
    }

    return result;
}

用法:

offSpring("layerA.layerB.layerC").y = 200;

答案 1 :(得分:1)

由于我不是静态属性的忠实粉丝所以我也建议递归搜索:

public function findChild(d:DisplayObject, n:String):DisplayObject {
    var dc:DisplayObjectContainer = d as DisplayObjectContainer; if (!dc) return null;
    for (var i:int = 0; i < dc.numChildren; i++){
        var ch:DisplayObject = dc.getChildAt(i);
        if (ch.name == n || (ch = findChild(ch, n))) return ch;
    }return null;
}

并且您可以直接输入:

 var d:DisplayObject = findChild(stage, "childName");

在舞台上的任何地方找到名为childName的第一个孩子。

我刚刚编写并测试了一次,但我希望没问题。

<强>优点

  • 您无需执行任何其他步骤即可使用此方法。您甚至不需要为您搜索的孩子命名容器。
  • 您可以在任何DisplayObjectContainer开始搜索。
  • 如果您在某些时候决定需要将子表单容器A移动到容器B,如果它仍然是同一分支的一部分且具有唯一名称,则不需要更改代码

<强>缺点

  • 这可能很昂贵,特别是如果你有广泛的分支。
  • 您需要确保您的孩子的名字在搜索的分支中是唯一的。

更复杂的版本

由于被搜查的孩子通常可以是给定容器的直接孩子,或者在更近的水平上,你可能会在一个时间点搜索孩子,尽管这有点棘手。例如我的alpha版本:

/**
 * Perform parallel/sprial recursive search in this container to find child with given name.
 * This means that this function will first check names of all child of this container and and then go to deeper level.
 * In other words, no element will be tested on level x+1 if not all elements were tested on level x.
 * This is true for all levels until whole tree is exhausted. This method is using token argument for such functionallity.
 * @param   n name of child element to be found.
 * @param   t token passed internally for sipral search. You should not specify this if you want the function to search a whole tree.
 * The token has only single value which is basically a desired level at which child should be searched for.
 * Level 1 means this function will only check its own childrens, level 2 means that only childs of childs of this container will be checked and so one.
 * However note that if you specify a token with some level, only that single level will be searched.
 * On the other hand if given token is null, this will check childs on level 1, then level 2, 3... and it will countinue until deepest level has been reached. 
 * @return nearest child with specified name or null if no child with given name found.
 */
public function findChild(n:String, t:SearchToken = null, ind:String = ""):SGLElement {
    ind += "    ";
    var r:Boolean = (t) ? false : true; //is this call root of search.
    t = (t) ? t.offL( -1) : new SearchToken(0); //create new token if not given or decrement current token value. 
    //trace(ind + "F", this.name, ":", t);
    //if (!t) t = new SearchToken(0);
    //--t.l;
    var cl:SearchToken = new SearchToken(t.l); //current search level.
    var exc:int = 0; //exhausted childrens.
    if(t.l == 0){//search own children
        for (var i:int = 0; i < _childs.length; i++) { //trace(ind + "  c", _childs[i].name);
            if (_childs[i].name == n) return _childs[i]; }
        if (r) ++cl.l; else return null;
    }
    while( cl.l > 0){
        if (exc >= _childs.length) { t.l = -1; return null;}
        for (i = 0; i < _childs.length; i++) {
            //trace(ind + "ch", t,":", i, _childs[i].name, _childs[i]);
            if (!(_childs[i] as SGLElementContainer)) continue;
            //trace(ind + "t", t, i);
            t.l = cl.l;
            var e:SGLElement = SGLElementContainer(_childs[i]).findChild(n, t, ind);
            //++cl.l;
            if (e) return e;
            else if (t.l < 0) exc++;
        }
        //trace(ind + "END_LEVEL>>>>", t);
        if (!r) return null;
        //t.l = cl.l; 
        ++cl.l;
    }
    return null;
}

令牌类

package adnss.common.utils 
{
    public class SearchToken 
    {
        /**Current level**/
        public var l:int;

        public function SearchToken(levelValue:int) {l = levelValue;}

        public function toString():String {return String(l);}

        /**Set level value and return this token instance.**/
        public function setL(v:int):SearchToken { l = v; return this; }

        /**Add given offset value to level value and return this token instance.**/
        public function offL(v:int):SearchToken { l += v; return this;} 
    }

}

我注意到我不知道这种搜索的技术名称是什么,所以我给它自己的名字,这个方法不用于显示列表,所以你需要调整它。这有点难以解释,但如果你有一些问题可以自由提问。