Skip to main content
May 31, 2011
Question

stage.stageWidth or stage.fullScreenWidth

  • May 31, 2011
  • 2 replies
  • 26446 views

When developing a multiscreen game or app, developers need to read device's screen size to correctly rescale and reorganise screen elements.

I have been always using stage.fullScreenWidth and stage.fullScreenHeight instead of stage.stageWidth and stageHeight as I heard from other developers that the returned values may be incorrect on some devices. But when I tested my app on Motorola Xoom which has Android 3.0 I noticed that a bottom bar that comes from operating system with Home / Back buttons covers my app (Motorola Xoom doesn't have hardware buttons so they are available on the screen). So AIR returns the full height value, including that bottom bar, what causes my app to be behind it. There are some buttons in the app that could not be reached because of that.

I have tested my app on few Android devices available to me against stage.stageWidth and stageHeight and I got correct values. Can anybody confirm if there are still issues on any devices including iOS? Maybe that was only a problem with AIR 2.0 and 2.5?

This topic has been closed for replies.

2 replies

Inspiring
February 12, 2012

These sizing issues can be very frustrating, especially as behavior is not the same across OSes and devices.  This is kind of critical stuff: you would think Adobe would have nailed this some time ago.

A lot of it is adapted from http://sierakowski.eu/list-of-tips/82-starting-with-air-for-android-and-ios-building-one-app-for-both-platforms.html, with some enhancements on my part to address the issue raised by sigman.pl, in this thread.

Please, anyone, feel free to correct me if you feel I am going about this the wrong way.

Here is what I do:

private static var _resizeEventFiredOnceAlready:Boolean;

private static const _screenBounds:Rectangle = Screen.mainScreen.visibleBounds;

private var _stageWidth:Number; // Don't get confused: for our use, we mean the SHORTEST visible screen length for the app, irrespective of device orientation.  Think of the app being in portrait mode (unlike in Sierakowski's blog)

private var _stageHeight:Number; // LONGEST visible screen length for the app. 

public function MyDocClass():void

{

    addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);

}

private function onAddedToStage(evt:Event):void

{

      removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage); // remove this handler

     // Below: we only do this once, when the app starts, since another one of this may be instanced later, possibly.

     if (!_resizeEventFiredOnceAlready)

     {

        // Below: we don't want to add (and build) our graphic assets to (based on)

        // a stretched stage.

        // Rather, we want to build them at the right size, which means we will need

        // to know the device screen size in a moment...

         stage.align = StageAlign.TOP_LEFT;

         // Above: if there is a top status bar, top_left is nevertheless right below it, so we're good...

         stage.scaleMode = StageScaleMode.NO_SCALE;

         // Above: needs to be set to no_scale, otherwise the resive event, below, won't fire when the app window changes its

         // its width or height.  That's a how the RESIZE event is supposed to work.

         // The default, otherwise, is "SHOW_ALL", which stretches the stage to fit within the window, but does not theorically

         // fire the resize event, though it does on iOS ( but not on Android, which is the correct behavior ) *

         // * I wished Adobe would fix these inconsistencies...

         stage.addEventListener(Event.RESIZE, onResize);

     }

     else

          initThis();

}

private function onResize(e:Event):void

{

    stage.removeEventListener(Event.RESIZE, onResize); // remove this handler

    _resizeEventFiredOnceAlready = true;

    // Determine screen size so that we can properly construct our UI...

    //

    // The problem with fullScreenWidth/Height is that it gives the entire

    // screen dimension, including the area occupied by optional status bars

    // (in cases where user set <fullScreen>false</fullScreen>, in the app manifest)

    // as well as the non-optional (so I read in this thread from sigman.pl) virtual Android buttons bar,

    // on some devices (ex: Xoom w/ Android 3.0).

    //

    // These status and buttons bars have the potential of causing important UI widgets

    // to be partially hidden, so we need to size our app so that it fits nicely within

    // the visible area of the screen: hence the use of Screen.mainScreen.visibleBounds.

    //

    // However, when debugging the app on a computer (CTRL+Enter in Flash CS5),

    // Screen.visibleBounds returns the area of the desktop, not the area within the flash window,

    // so that's annoying (note: Screen.screens doesn't work as of this writing *).  Also, there is no guarantee that in the

    // future,mobile OSes might not be able to start apps in a 'minimized' mode (like a computer),

    // so we will use Math.min to address both issues, below.

    // * Another important unfinished loose end from Adobe

    //

    // Note: stage.stageWidth/Height would have returned the stage dimensions as was set in CS5,

    // regardless of what scaleMode is set at ( scaleMode only affects what the stage looks like,

    // stretched or not, on the device, but does not affect the values returned by stageWidth/Height ).

    _stageWidth = Math.min( stage.fullScreenWidth, _screenBounds.width );

    _stageHeight = Math.min( stage.fullScreenHeight, _screenBounds.height );

   // Above: fullScreenWidth and _screenBounds.width always refer to the same side of the screen,

   // on any OS and device AFIK, so we're comparing apples to apples.

    // Apparently, according to Sierakowski's blog (see link above), stage.fullScreenWidth isn't consistent in always giving the

    // same (shortest screen length), when the device is started in landscape mode between iOS and Android *.

    // Anyway, let's make sure we always get the shortest screen length:

    // * Another Adobe loose end, though I believe this has been fixed in 3.1 (maybe even earlier). 

    var temp:Number = _stageWidth;

    _stageWidth = Math.min( _stageWidth, _stageHeight );

    _stageHeight = Math.max( temp, _stageHeight );

    // Above: now _stageWidth is always the shortest screen length / and _stageHeight the longest one, irrespective

    // of if we started the app in landscape mode or not.  We could now swap the 2 at this point, based on device orientation,

    // but at least we know what is what.

    // Rest of your code

    initThis();

}

Note:

My personal preference is to always have my apps run in fullscreenMode = true / aspectRatio = portrait / autoOrients = false, only.  If there is a need to redraw/resize stuff based on a change in orientation, then a handler should be able to 'fake' it, rather than actually modifying the stage.

The stage is the stage, let's not f*** with it!  It's hard enough as it is...

Participating Frequently
March 17, 2013

It worked! It worked fantastically. I abandoned stage.fullScreenHeight, stage.stageHeight,  and Capabilities.screenResolutionY. because these all come close but if the Android has Virtual buttons my bottom navigation was covered and if the device didn't have virtual button but physical buttons (i.e. most phones. Then the bottom navigation was too high and did not rest on the bottom of the screen.

Thank you AsterLUXman for posting this. Saved a few times pounding my head against the wall.

Projectitis
Inspiring
March 12, 2014

IMPORTANT - BUG IN ABOVE CODE (AsterLUXman).

Not sure if something has changed since this post was written.  I am using AIR 13 on iPhone5 (iOS7) and this assumption is not correct:

_stageWidth = Math.min( stage.fullScreenWidth, _screenBounds.width );

_stageHeight = Math.min( stage.fullScreenHeight, _screenBounds.height );

// Above: fullScreenWidth and _screenBounds.width always refer to the same side of the screen,

// on any OS and device AFIK, so we're comparing apples to apples.

In my situation:

  • Screen.mainScreen.visibleBounds does NOT change with orientation change
  • However, stage.fullScreenWidth and stage.fullScreenHeight swap places during orientation change

Here is my code. I call it once when the game is created/initialised, and then in the onResize event:

var minBound : Number = Math.min( Screen.mainScreen.visibleBounds.width, Screen.mainScreen.visibleBounds.height );

var maxBound : Number = Math.max( Screen.mainScreen.visibleBounds.width, Screen.mainScreen.visibleBounds.height );

if (stage.fullScreenWidth > stage.fullScreenHeight) {

           // Landscape

           screenWidth = Math.min( stage.fullScreenWidth, maxBound );

           screenHeight = Math.min( stage.fullScreenHeight, minBound );

}

else {

           // Portrait

           screenWidth = Math.min( stage.fullScreenWidth, minBound );

           screenHeight = Math.min( stage.fullScreenHeight, maxBound );

}

Note: Unlike the code sample given by AsterLUXman, the above code doesn't swap the dimensions to always keep them in portrait. If you always want the dimensions in portrait mode, use:

var minBound : Number = Math.min( Screen.mainScreen.visibleBounds.width, Screen.mainScreen.visibleBounds.height );

var maxBound : Number = Math.max( Screen.mainScreen.visibleBounds.width, Screen.mainScreen.visibleBounds.height );

if (stage.fullScreenWidth > stage.fullScreenHeight) {

           // Landscape. Note: swaps dimensions to always give them in portrait mode

           screenHeight = Math.min( stage.fullScreenWidth, maxBound );

           screenWidth = Math.min( stage.fullScreenHeight, minBound );

}

else {

           // Portrait

           screenWidth = Math.min( stage.fullScreenWidth, minBound );

           screenHeight = Math.min( stage.fullScreenHeight, maxBound );

}

May 31, 2011

Just tested on iPhone and noticed that it returns original stage size rather than the actual.

I use

stage.scaleMode = StageScaleMode.NO_SCALE;

stage.align = StageAlign.TOP_LEFT;

and I wait for Event.RESIZE before reading these values...

relaxatraja
Inspiring
June 1, 2011

create a timer and read your stage values frequently. Or test with the Orientation event.