Stage RESIZE and the stageWidth and stageHeight Bug

A while ago, I came across a situation where my Flash application would launch but the stage.stageWidth and stage.stageHeight properties would always return 0 within my document class’s constructor. As I needed to access those properties at runtime and I did not want to hardcode those values to a pair of variables, it drove me to seek an answer to this problem.

Turns out that when the stage is initialized, its stageWidth and stageHeight properties are 0 until a Stage RESIZE event is triggered. This event is dispatched when the scaleMode property of the Stage object is set to StageScaleMode.NO_SCALE and the SWF file is resized ie. when the stage is rendered by the Flash Player. So if you need to add a display object onto the stage and its positioning is dependent on the stageWidth or stageHeight properties at runtime, it’s best handled by a listener that is subscribed to the Stage RESIZE event.

Interestingly, despite universal claim that the Flash Player behaves exactly the same on all browsers, this problem only appears in a couple of browser/plugin configurations, namely FireFox/OSX and IE/Win. And strangely, on Safari and Firefox/Win, the RESIZE event is not even dispatched on page load, and neither does the Flash Player register the stageWidth and stageHeight properties as being 0. I have not tested the problem on other platforms but you are certainly welcome to do so yourselves and report your observations in the comments section. Eventually, it would be nice if we can get a straight answer from Adobe concerning this bug.

In the following demo code, I’ve attached a Sprite containing a Rectangle graphic and a TextField, to the stage once before the RESIZE event and once, after. You can see the results here.

package
{
  import flash.text.*;
  import flash.display.*;
  import flash.events.*;

  public class Demo extends Sprite
  {
    private var rect1:Sprite;
    private var rect2:Sprite;

    public function Demo()
    {
      rect1 = createNewRect("Before stage resize event.");
      rect1.x = 0;
      rect1.y = 0;
      addChild(rect1);

      stage.scaleMode = StageScaleMode.NO_SCALE;
      stage.align = StageAlign.TOP_LEFT;
      stage.addEventListener(Event.RESIZE, resizeHandler);
    }

    private function createNewRect(str:String):Sprite
    {
      var rect:Sprite = new Sprite();
      rect.graphics.beginFill(0x99CCFF);
      rect.graphics.drawRect(0, 0, 200, 100);
      rect.graphics.endFill();

      var fmt:TextFormat = new TextFormat();
      fmt.font = "Arial";
      fmt.size = 12;

      var tf:TextField = new TextField();
      tf.width = 200;
      tf.height = 100;
      tf.multiline = true;
      tf.defaultTextFormat = fmt;
      tf.text = str + "\n" + "stage.stageWidth: " + stage.stageWidth + "\n" +
            "stage.stageHeight: " + stage.stageHeight;

      rect.addChild(tf);
      return rect;
    }

    private function resizeHandler( event:Event ):void
    {
      if (rect2 != null && contains(rect2)) {
        removeChild(rect2);
      }

      rect2 = createNewRect("After stage resize event.");
      rect2.x = (stage.stageWidth - rect2.width) / 2;
      rect2.y = (stage.stageHeight - rect2.height) / 2;
      addChild(rect2);
    }
  }
}
Share/Save/Bookmark

23 Responses to “Stage RESIZE and the stageWidth and stageHeight Bug”

  1. Adam Says:

    A solution that I have found that seems to work across all browsers – although its very dirty – is to set a timer when the app begins. Every time the timer goes off (every 200 ms or so) it checks to see if stage.stageWidth == 0. If that is the case, do nothing. If that’s NOT the case, then stop the timer and begin the app.

  2. Peng Says:

    Thanks, Adam. Yes, that’s one solution. The other option is to use an ENTER_FRAME listener and perform the same check on stage.stageWidth.

  3. Eugene Says:

    Now everyone is talking about the American economy and eclections, nice to read something different. Eugene

  4. Gertjan.com Says:

    I just came across this problem…
    It appears to only be the case when I compile via Flex SDK (instead of IDE).

    Any better solutions?

  5. erik van nieuwburg Says:

    A good old FrameDelay usually does the trick….. AsapLibrary has this class, which is pretty great :-)

    http://asaplibrary.org/api/html/org_asaplibrary_util_FrameDelay.html

  6. Mac?Firefox 3?stage.stageWidth????????? : boreal-kiss.com Says:

    [...] Stage RESIZE and the stageWidth and stageHeight Bug | hubflanger.com | adventures in code [...]

  7. Peng Says:

    Erik, cool. Will give that a try.

  8. Wilson Says:

    I’m familiar with this, it usually happens when you’re subclassing objects from the library that have a lot of other classes imported. Use the flash.events.Event.ADDED_TO_STAGE and therefore delay your init. You’ll get your stage properties from the root at that point.

  9. jvc Says:

    Wilson: I have been able to replicate this in simple one Class tests with out any Objects in the Library

  10. dietlev Says:

    Code below, this seems to work for me on all browsers :
    Preloader is the document class of my project

    // ———————————————

    public function Preloader()
    {
    _isReady = false;

    stage.scaleMode = StageScaleMode.NO_SCALE;
    LayoutManager.getInstance().setStage(this.stage);
    Model.STAGE = stage;
    stage.frameRate = 31;

    stage.addEventListener( Event.RESIZE,stage_resizeHandler);

    _stageTimer = new Timer(200);
    _stageTimer.addEventListener( TimerEvent.TIMER,timer_tickHandler);
    _stageTimer.start();
    }

    private function timer_tickHandler(event : TimerEvent) : void
    {
    if ( Model.STAGE.stageWidth > 0 && Model.STAGE.stageHeight > 0 )
    {
    initPreloader();
    }
    }

    private function stage_resizeHandler(event : Event) : void
    {
    if ( Model.STAGE.stageWidth > 0 && Model.STAGE.stageHeight > 0 )
    {
    initPreloader();
    }
    }

    private function initPreloader() : void
    {
    if ( !_isReady )
    {
    _isReady = true;
    _stageTimer.stop();
    stage.removeEventListener( Event.RESIZE,stage_resizeHandler);

    initBackground();
    initContainers();
    init( );
    }

    }

  11. Peng Says:

    @dietlev This looks like an excellent solution. Thanks!

  12. Deju Playground » stageWidth and stageHeight bug in Firefox/OS X and IE/Win using SWFObject Says:

    [...] swf files differently from other browsers. You can read more in depth about this issue here and here, so I won’t repeat what others have said. My solution to this issue was to add a ENTER_FRAME [...]

  13. Juan Develops Says:

    i wrote generic code that will handle this problem both in flash and flex…

    http://juandevelops.wordpress.com/2009/03/16/issues-happening-when-event-listener-on-stage-added-occurs/

    thanks for all your posts.. :)

  14. Issues happening when event listener on stage added occurs. « Juan develops in AS 3.0 Says:

    [...] in IE for windows having swf being non-scale, and being embedded using swfobject.  In this site: http://hubflanger.com/stage-resize-and-the-stagewidth-and-stageheight-properties. They mentioned that the stage dimensions can be returned as 0.  they recommend to target instead [...]

  15. StorUrsa Says:

    I see this as a bug only if the Demo is serving as the document class.

    If it’s not serving and the document class then I assume this is the code you are using:
    var d:Demo = new Demo(); <– at this point the DisplayObject doesn’t get a reference to stage
    addChild(d); <– at this point the DisplayObject does have a reference to stage.

    The stage reference gets set on DisplayObjects once they are added to the stage.

    I get why they did this, and DisplayObject shouldn’t know anything about the stageWidth or stageHeight, before it is added to a certain stage. Just as the DisplayObject doesn’t have a parent before it is added to the Display List.

    But I also understand why you expect stage to be defined, because for all intents and purposes the stage object is a global variable and should be accessible by any subclass of DisplayObject. Problem is when do you set the stage reference. In the DisplayObject constructor, of course…. Wait… The DisplayObject is an abstract class and a call the the constructor throws an ArgumentError.

    So the only logical place to set it is when a DisplayObject is added to the stage.

  16. Will Says:

    Great! I was pulling my hair out trying to figure out why this was happening. The following code seems to work for me without the need to mess around with timers, frame events etc. The following would go in a document class called Main.

    public function Main():void {
    stage.align = StageAlign.TOP_LEFT;
    stage.scaleMode = StageScaleMode.NO_SCALE;
    this.loaderInfo.addEventListener(Event.COMPLETE, init);
    }
    private function init(e:Event):void {
    if (stage.stageWidth == 0 || stage.stageHeight == 0) {
    stage.addEventListener(Event.RESIZE, init);
    } else {
    // Init stuff goes here!
    }
    }

  17. Randall Says:

    Try your demo in Google Chrome. Grabbing the bottom of the window and resizing vertically does not trigger the RESIZE event. Horizontal resize works as expected. Also the same case in Safari for Mac/OSX although tougher to replicate since you can only resize with the corner of the window. Looks like a problem with WebKit. Very frustrating.

  18. Stage.stageWidth and stage.stageHeight bugs in certain browsers « Jufa Says:

    [...] http://hubflanger.com/stage-resize-and-the-stagewidth-and-stageheight-properties/ « FITC Edmonton [...]

  19. NS Says:

    I am having the same problem as Randall mentioned. My flex app do not load in Google Chrome ; if I resize the window, it loads up fine.

  20. RCDMK Says:

    I was having the same issue. My solution was to use the standard Main class FlashDevelop creates, with the ADDED_TO_STAGE event, that fires a init function:
    public function Main():void
    {
    if (stage) init();
    else addEventListener(Event.ADDED_TO_STAGE, init);
    }

    private function init(e:Event = null):void
    {
    removeEventListener(Event.ADDED_TO_STAGE, init);
    // entry point

    stage.scaleMode = StageScaleMode.EXACT_FIT;
    var grafico:Grafico = new Grafico();

    grafico.Desenhar();
    grafico.x = (stage.stageWidth – grafico.width) / 2;
    grafico.y = (stage.stageHeight – grafico.height) / 2;

    addChild(grafico);
    }

    Hope that it heps.

  21. koi fish Says:

    One of the terrific features about blogs is the capability to empower all of us to share many thoughts on the world wide web. Sometimes it’s just amazing to blast away your thoughts and get it out of your head. And you want to know what’s fabulous about it? It doesn’t matter what the subject is! There will always be an interested party to read what you’ve written. Saying by koi. Thank you for sharing yours.

  22. Yahoo Movie News Says:

    Yahoo News…

    This is really great news today….

  23. borriej Says:

    please help me out, I’ve read all of the above, but couldnt find a solution for my flash to be scaled by FireFox at refresh. When I resize the window it will work, but it should resize on a simple F5…

    AS 2.0:

    new FrameDelay(init);
    Stage.align = “TL”;
    Stage.scaleMode = “noScale”;
    sizeListener = new Object();
    sizeListener.onResize = function() {
    trace(Stage.width);
    trace(Stage.height);
    txt_width=Stage.width;
    txt_height=Stage.height;
    trace (width);

    onderkant._x = Stage.width – 691;
    Afb_mc._x = Stage.width – 267;

    };
    Stage.addListener(sizeListener);
    stop();

Leave a Reply