AS3でタイムラインでgotoAndStop()やgotoAndPlay()を呼んだ直後、ステージに配置した要素にアクセスできないのは有名な話ですが、この現象の解決策があるようです。

Enabling Access to Timeline Items in AS3 after gotoAndStop()をざっくり意訳してみました。

Waiting a frame (using a callLater or simply hooking into one ENTER_FRAME event broadcast) will not be long enough. But there is another event dispatched by Stage which might work, Event.RENDER.

[意訳]1フレームの生成を待つの(calLlater関数を使うか、単純にENTER_FRAMEイベントの配信に引っ掛ける)のに時間はかからないが、もうひとつ、Stageに割り当てられたEvent.RENDERという 使えるイベントがあります。

I think the event sequence goes something like this:

[意訳]イベントシーケンスは次のようになっていると思います。

  1. myTitleField is defined here
  2. gotoAndStop( “step2″ );
  3. myTextField is null here
  4. Event.ENTER_FRAME is dispatched
  5. myTitleField is still null here
  6. Any code written on the keyframe itself is executed
  7. stage’s Event.RENDER is dispatched
  8. myTitleField is defined again!

[意訳]

  1. myTitleFieldが定義されます
  2. gotoAndStop( “step2″ );
  3. ここではmyTextFieldがnullになります
  4. Event.ENTER_FRAMEが配信されます
  5. myTitleFieldはまだnullです
  6. キーフレーム上のコードが実行されます。
  7. ステージの Event.RENDER が配信されます
  8. myTitleField が再び現れます

So thanks to a tip from Senocular, the RENDER event looks like what we need. To force this event to fire, you must call stage.invalidate(), also the event is only dispatched to items on a DisplayList, and on top of that, it doesn’t go through a typical capture phase, the event is broadcast directly to the DisplayObject, but that shouldn’t matter here.

[意訳]SenocularのTipsに感謝します。RENDERイベントはまさにわれわれが必要としていたものだった。このイベントを発行させるためにstage.invalidate()を呼ぶ必要がありますが、またこのイベントはDisplayList上の要素と、その上の要素に対してのみ発行され、典型的なキャプチャフェーズは通らず直接DisplayObjectに配信されますが、注意することではありません。

Ok so a sample might now look like this:

[意訳]次のようにすれば大丈夫。

public var myTitleField: TextField; protected function onAddedToStage( event: Event ): void { myTitleField.text = "Step" + currentStep; // All good stage.addEventListener( Event.RENDER, onStageRender ); } protected function showNextStep(): void { gotoAndStop( "step" + currentStep ); stage.invalidate(); } protected function onStageRender( event: Event ): void { myTitleField.text = "Step" + currentStep; // myTitleField is null! }

stage.invalidate()を呼ぶことで次のRENDERイベントをひろうことができます。

RENDERイベントって何に使うの?っていう話もありましたが、要するに表示する直前に表示要素をなにかすることで描画パフォーマンスをかけずに処理する場面があるということみたいですね。(個人的にはあまりなさそうですが)

ただ、ADDED_TO_STAGEとRENDERイベントについて、FlashPlayerにバグがあるので注意とのことです。

Note: It’s important to remember that there are bugs related to both Event.ADDED_TO_STAGE and Event.RENDER (with wmode). So best be sure your viewers are using Flash Player 9.0.115.0 or greater to avoid a world of pain

[意訳]補足:忘れてはならない重要なことは、Event.ADDED_TO_SATGEとEvent.RENDER(wmode利用時)の両方ともに既知のバグがあることです。したがって、残念な思いをしないようあなたの閲覧者がFlashPlayer9.0.115.0以上を利用していることをよく確認してください。

HTML5飯