2010年9月21日 星期二

簡單談走訪某個DisplayObjectContainer底下的所有DisplayObject

最近遇到一個需求:在user按下某個按鈕後要讓畫面上所有的動態停下來,而且有5個檔案要這樣做,其中幾個元件還頗複雜,因為加了很多效果。顯然,要手動去停止所有MovieClip會做到死,記得之前有看過走訪某個DisplayObjectContainer底下的所有DisplayObject的範例,就是殿堂之路這本書。

先把這段程式碼貼出來:
private function stopAll(container:DisplayObjectContainer):void
{
  var child:DisplayObject;
  for (var i:uint = 0; i < container.numChildren; i++)//檢查container底下的所有可視物件
  {
    child = container.getChildAt(i);//依深度來取出子物件
    if (child is MovieClip) {//如果子物件是MovieClip時就停下來
      MovieClip(child).stop();
    }
    if (container.getChildAt(i) is DisplayObjectContainer)//如果子物件也是個DisplayObjectContainer,就檢查看看裡面是否有子物件
    {
      stopAll(DisplayObjectContainer(child));//是的話就再呼叫一次,這裡就變成了遞迴函式
    }
  }
}
用這個方法,我們也可以做其他應用,例如幫某個容器底下的所有MovieClip加上addFrameScript,在最後一個影格加上stop();,這在使用Embed Symbol到AS再去發佈時可能很有用,不過前提是這些MovieClip在跑這遞迴函式時有出現在時間軸上。我們也可以寫個比較有彈性的應用,例如把上面這個function放到一個常用的Util類別裡,然後多設個callback參數讓我們傳入callback function,在實際要處理的那段,就改成把child丟進callback function裡,好處就是遞迴的部分是固定的,不用每次寫,而真正處理的部分可能要常常換,就寫在callback function裡。 實際走訪的速度,其實很快,所以不用擔心效能問題,除非是超大量的物件,那就要測測看了。

2 則留言:

  1. 如果container本身是MovieClip類別的話
    你的stopAll就不會幫container下stop動作了

    這是我之前寫的遞迴你參考看看:)
    function stopAll(c:DisplayObjectContainer):void
    {
    var length:int = c.numChildren;
    for (var i:int = 0; i < length; i++ )
    {
    var child:DisplayObject = c.getChildAt(i);
    if(child is DisplayObjectContainer) stopAll(DisplayObjectContainer(child));
    }
    if (c is MovieClip) MovieClip(c).stop();
    }

    ps.跟你的差在判斷MovieClip那段放的位置以及判斷的對象不一樣

    回覆刪除
  2. To Sam:
    嗯,我確實沒考慮到cantainer本身,謝啦

    回覆刪除