Adobe
Products
Acrobat
Creative Cloud
Creative Suite
Digital Marketing Suite
Digital Publishing Suite
Elements
Photoshop
Touch Apps
Student and Teacher Editions
More products
Solutions
Digital marketing
Digital media
Education
Financial services
Government
Web Experience Management
More solutions
Learning Help Downloads Company
Buy
Home use for personal and home office
Education for students, educators, and staff
Business for small and medium businesses
Licensing programs for businesses, schools, and government
Special offers
Search
 
Info Sign in
Welcome,
My cart
My orders My Adobe
My Adobe
My orders
My information
My preferences
My products and services
Sign out
Why sign in? Sign in to manage your account and access trial downloads, product extensions, community areas, and more.
Adobe
Products Sections Buy   Search  
Solutions Company
Help Learning
Sign in Sign out My orders My Adobe
Preorder Estimated Availability Date. Your credit card will not be charged until the product is shipped. Estimated availability date is subject to change. Preorder Estimated Availability Date. Your credit card will not be charged until the product is ready to download. Estimated availability date is subject to change.
Qty:
Purchase requires verification of academic eligibility
Subtotal
Review and Checkout
Adobe Developer Connection / Adobe AIR Developer Center /

Supporting the multiple screen sizes of multiple devices in Adobe AIR

by Sarah Northway

Sarah Northway
  • Northway Games

Content

  • Detecting screen size
  • Forcing orientation
  • Calculating physical dimensions
  • Scaling and centering an interface
  • Converting vectors to scaled bitmaps
  • Detecting and limiting Apple iOS devices
  • Limiting Android devices
  • Where to go from here

Created

11 June 2012

Page tools

Share on Facebook
Share on Twitter
Share on LinkedIn
Bookmark
Print
ActionScript Adobe AIR Android gaming iOS mobile multiscreen

Requirements

Prerequisite knowledge

An intermediate understanding of developing Adobe AIR applications for mobile devices and programming in ActionScript 3 will help you make the most of this article.

User level

Intermediate

Required products

  • Flash Professional (Download trial)
  • Flash Builder (Download trial)
  • Adobe AIR

Whether you're adapting a game that runs in Flash Player in the browser to run on iOS (using Adobe AIR) or writing an Adobe AIR application for Android tablets, you'll need to support at least a few different screen resolutions. My post-apocalyptic strategy game Rebuild (for more background, read the Rebuild postmortem) was designed to be played in the browser with Flash Player at 800 x 600 pixels, so it took a few tricks to adapt it to run on the plethora of mobile devices out there.

In this article, I share some of those tricks (based on Adobe AIR 3.2) and sample code for:

  • Detecting screen size
  • Forcing orientation
  • Calculating physical dimensions
  • Scaling and centering an interface
  • Converting vectors to scaled bitmaps
  • Detecting and limiting Apple iOS devices
  • Limiting Android devices

Detecting screen size

There are four different ways to check dimensions.

The stage.width and stage.height properties indicate the width and height of the contents of the stage in pixels. If your SWF file is 500 x 500 pixels and contains a 100 x 100 pixel square, these properties will return 100 x 100.

You can use stage.stageWidth and stage.stageHeight to access the current width and height, in pixels, of the size of your SWF file in either Flash Player or Adobe AIR. In the above scenario, they would return 500 and 500 . They may be set incorrectly during the first few frames. In StageScaleMode.NO_SCALE , a resize event is triggered when these change.

The stage.fullScreenWidth and stage.fullScreenHeight properties return the width and height of the screen when going to full size, including space taken up by toolbars. These properties only change when width and height are swapped because of a change in orientation.

Lastly, the Capabilities.screenResolutionX and Capabilities.screenResolutionY properties return the maximum horizontal and vertical resolutions of the screen. In other words, they tell you the size of the device's entire screen. If your game is running in a window (for example, in a simulator on your computer), these properties will still return the size of the entire monitor.

Ideally, your application should check stage.stageWidth and stage.stageHeight , then listen for resize events (which includes changes in orientation). Depending on the device, these values may be completely wrong at first, and then after a few seconds you'll see several resize events as the application becomes fullscreen, toolbars disappear, and orientation corrects itself. Here's how to check resolution on the fly:

private static function handleResize(...ig) :void { var deviceSize:Rectangle = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight); // adjust the gui to fit the new device resolution } stage.addEventListener(Event.RESIZE, handleResize); // call handleResize to initialize the first time handleResize();

For my game Rebuild, I wanted to get the dimensions a single time as soon as the game started, so I could initialize the GUI only once. The Stage.fullScreenWidth and Stage.fullScreenHeight properties provide a better approximation in this case, although they don't include any system toolbars that appear above your application (for example, those found on the Kindle Fire). The orientation may also be wrong, but because my game forces landscape orientation, I can assume that the wider dimension is always width, like this:

var deviceSize:Rectangle = new Rectangle(0, 0, Math.max(stage.fullScreenWidth, stage.fullScreenHeight), Math.min(stage.fullScreenWidth, stage.fullScreenHeight));

Forcing orientation

In your application.xml file, you can set the default aspectRatio to either landscape or portrait . For iOS this also determines which splash screen graphic you need— Default-Landscape.jpg or Default-Portrait.jpg . If you want to support both modes, set autoOrients to true , in which case a resize event will fire any time the user tilts the device to change orientation. Your application may briefly start in the wrong orientation even when autoOrients is set to false .

I use the following setup to force landscape orientation:

<initialWindow> <visible>true</visible> <fullScreen>true</fullScreen> <autoOrients>false</autoOrients> <aspectRatio>landscape</aspectRatio> <renderMode>gpu</renderMode> ... </initialWindow>

I change aspectRatio to force portrait orientation:

<initialWindow> <visible>true</visible> <fullScreen>true</fullScreen> <autoOrients>false</autoOrients> <aspectRatio>portrait</aspectRatio> <renderMode>gpu</renderMode> ... </initialWindow>

For games like Rebuild it's generally accepted to stick to one aspect ratio rather than switch back and forth, however most applications usually support both aspect ratios.

Calculating physical dimensions

Although a small phone and a large tablet could have the same number of pixels, they would have very different physical sizes. For example, when you touch an iPhone 4's retina 960 x 640 display, your finger covers four times more pixels than when you touch an iPad 1's 1024 x 768 screen. This is important to consider for legibility of fonts and icons, and particularly for the size of buttons.

Looking at the dots-per-inch (more properly called PPI or pixels-per-inch), you can estimate how big your interface should be to avoid fat-finger mistakes. Apple suggests the minimum size for buttons and interactive objects should be 44 x 44 pixels for a 163 dpi screen (for example, an iPhone 3GS).

Android uses the concept of density-independent pixels (dp), which is a normalized pixel unit for defining resolution compared to a 160 dpi screen. A device's dp is calculated as pixels * 160 / DPI. To determine the dpi, dp, and size in inches you can use the following code:

var dpi:Number = Capabilities.screenDPI; var dpWide:Number = stage.fullScreenWidth * 160 / dpi; var inchesWide:Number = stage.fullScreenWidth / dpi;

Unfortunately devices often report the wrong dpi (notably for iOS displays). Capabilities.screenDPI is actually a best guess based on other information, but it may also be wrong. For comparison, you can get the original dpi reported by the operating system as follows:

var serverString:String = unescape(Capabilities.serverString); var reportedDpi:Number = Number(serverString.split("&DP=", 2)[1]);

Rebuild's iOS build has two static interface layouts: one for iPad and another with larger text and buttons for iPhone and iPod Touch. You can use the current device's dpi and physical size to pick which layout to use.

Scaling and centering an interface

Adobe AIR has several built-in scaling modes, but I found that SHOW_ALL and EXACT_FIT behave oddly on devices. To have full control of scaling on devices (especially useful when resizing bitmaps), I found it's best to use NO_SCALE and handle scaling yourself.

Rebuild for Android uses a 1024 x 600 GUI that gets scaled up or down accordingly, then centered horizontally at the top of the screen. It's done when the game first loads, like this:

stage.scaleMode = StageScaleMode.NO_SCALE; stage.align = StageAlign.TOP_LEFT; var guiSize:Rectangle = new Rectangle(0, 0, 1024, 600); var deviceSize:Rectangle = new Rectangle(0, 0, Math.max(stage.fullScreenWidth, stage.fullScreenHeight), Math.min(stage.fullScreenWidth, stage.fullScreenHeight)); var appScale:Number = 1; var appSize:Rectangle = guiSize.clone(); var appLeftOffset:Number = 0; // if device is wider than GUI's aspect ratio, height determines scale if ((deviceSize.width/deviceSize.height) > (guiSize.width/guiSize.height)) { appScale = deviceSize.height / guiSize.height; appSize.width = deviceSize.width / appScale; appLeftOffset = Math.round((appSize.width - guiSize.width) / 2); } // if device is taller than GUI's aspect ratio, width determines scale else { appScale = deviceSize.width / guiSize.width; appSize.height = deviceSize.height / appScale; appLeftOffset = 0; } // scale the entire interface base.scale = appScale; // map stays at the top left and fills the whole screen base.map.x = 0; // menus are centered horizontally base.menus.x = appLeftOffset; // crop some menus which are designed to run off the sides of the screen base.scrollRect = appSize;

The relative sizes and positions of objects inside the base stay the same regardless of scaling. For example, items in my scrolling inventory list are always spaced 50 pixels (px) apart. But you will need to adjust for scale any time you use MouseEvent.stageX , MouseEvent.stageY , or DisplayObject.localToGlobal .

Converting vectors to scaled bitmaps

The browser version of Rebuild uses vector objects for buildings, icons, buttons, and backgrounds. They look great when scaled and keep file sizes low, but that scaling can be too complex to render efficiently on devices. They also use filters that aren't supported in GPU rendering mode in Adobe AIR and have jagged edges when stage.quality is lowered to increase performance. My solution is to replace them with bitmaps created at the scale I calculated earlier. I do this once when the game first loads.

If you don't use vectors, you can also use the code below to scale down large bitmaps to the needed size so they look smoother and take up less memory. However, bitmaps that include text or icons may become illegible if scaled down too far. You may get better results by having two or more sets of pre-rendered bitmaps and selecting one of them based on screen dpi.

// the original object's size (won't include glow effects!) var objectBounds:Rectangle = object.getBounds(object); objectBounds.x *= object.scaleX; objectBounds.y *= object.scaleY; objectBounds.width *= object.scaleX; objectBounds.height *= object.scaleY; // the target bitmap size var scaledBounds:Rectangle = objectBounds.clone(); scaledBounds.x *= appScale; scaledBounds.y *= appScale; scaledBounds.width *= appScale; scaledBounds.height *= appScale; // scale and translate up-left to fit the entire object var matrix:Matrix = new Matrix(); matrix.scale(object.scaleX, object.scaleY); matrix.scale(appScale, appScale); matrix.translate(-scaledBounds.x, -scaledBounds.y); // briefly increase stage quality while creating bitmapData stage.quality = StageQuality.HIGH; var bitmapData:BitmapData = new BitmapData(scaledBounds.width, scaledBounds.height, true); bitmapData.draw(object, matrix); stage.quality = StageQuality.LOW; // line up bitmap with the original object and replace it var bitmap:Bitmap = new Bitmap(bitmapData); bitmap.x = objectBounds.x + object.x; bitmap.y = objectBounds.y + object.y; object.parent.addChildAt(bitmap, object.parent.getChildIndex(object)); object.parent.removeChild(object); // invert the scale of the bitmap so it fits within the original gui // this will be reversed when the entire application base is scaled bitmap.scaleX = bitmap.scaleY = (1 / appScale);

If you need two or more of the same Bitmap object, you should save and reuse a single BitmapData object because it takes very little memory to create a second Bitmap object from it. Remember to call Bitmap.bitmapData.dispose() when you're done with it, to immediately remove it from memory rather than waiting for it to be garbage collected.

Detecting and limiting Apple iOS devices

The iPhone, iPad, and iPod touch report their names in Capabilities.os , so it's possible to detect exactly which one the game is running on and adjust accordingly. For example, Rebuild has fewer animations and smaller maps on the slower iPad 1 and iPhone 3GS. The following code shows how to detect the iOS device and adjust the game accordingly:

public static function getDevice():String { var info:Array = Capabilities.os.split(" "); if (info[0] + " " + info[1] != "iPhone OS") { return UNKNOWN; } // ordered from specific (iPhone1,1) to general (iPhone) for each (var device:String in IOS_DEVICES) { if (info[3].indexOf(device) != -1) { return device; } } return UNKNOWN; } public static const IPHONE_1G:String = "iPhone1,1"; // first gen is 1,1 public static const IPHONE_3G:String = "iPhone1"; // second gen is 1,2 public static const IPHONE_3GS:String = "iPhone2"; // third gen is 2,1 public static const IPHONE_4:String = "iPhone3"; // normal:3,1 verizon:3,3 public static const IPHONE_4S:String = "iPhone4"; // 4S is 4,1 public static const IPHONE_5PLUS:String = "iPhone"; public static const TOUCH_1G:String = "iPod1,1"; public static const TOUCH_2G:String = "iPod2,1"; public static const TOUCH_3G:String = "iPod3,1"; public static const TOUCH_4G:String = "iPod4,1"; public static const TOUCH_5PLUS:String = "iPod"; public static const IPAD_1:String = "iPad1"; // iPad1 is 1,1 public static const IPAD_2:String = "iPad2"; // wifi:2,1 gsm:2,2 cdma:2,3 public static const IPAD_3:String = "iPad3"; // (guessing) public static const IPAD_4PLUS:String = "iPad"; public static const UNKNOWN:String = "unknown"; private static const IOS_DEVICES:Array = [IPHONE_1G, IPHONE_3G, IPHONE_3GS, IPHONE_4, IPHONE_4S, IPHONE_5PLUS, IPAD_1, IPAD_2, IPAD_3, IPAD_4PLUS, TOUCH_1G, TOUCH_2G, TOUCH_3G, TOUCH_4G, TOUCH_5PLUS];

Although I've listed all Apple mobile devices above, you'll never need to support the first or second generation iPhone and iPod Touch, because they lack the necessary architecture (armv7) and graphical libraries (opengles-2) to run AIR 3.2 applications.

There are a few ways to further limit your application to only run on a subset of compatible iOS devices.

You can set your application to only target iPads, or only target iPhone/iPod Touch via UIDeviceFamily in application.xml; for example:

<iPhone> <InfoAdditions><![CDATA[ <key>UIDeviceFamily</key> <array> <!-- iPhone support --> <string>1</string> <!-- uncomment for iPad support <string>2</string> --> </array> ... ]]></InfoAdditions> </iPhone>

You can get more specific by setting UIRequiredDeviceCapabilities in the same application.xml. For example requiring a still-camera means the device must have a camera. Requiring a gyroscope conveniently limits your application to the newer iPhone 4+, iPod Touch 4+, and iPad 2+. Wikipedia has a definitive list of iOS devices and their features.

To enable double-density displays in iPhone 4S+ (iPad 3 retina support isn't yet available in AIR 3.2), set requestedDisplayResolution to high . This changes the reported screen resolution in iPhones from 480 x 320 (163 dpi) to 960 x 640 (326 dpi). Make sure your application scales down appropriately for the iPhone 3GS and iPod Touch 3gen, which don't support retina display.

<iPhone> ... <!-- requestedDisplayResolution standard (the default), or high. --> <requestedDisplayResolution>high</requestedDisplayResolution> </iPhone>

Limiting Android devices

There are nearly 1000 different Android devices. They don't report their names via Capabilities.os , and there is no way to determine the CPU capabilities or RAM of the device. However, you can target specific Android devices (for example just tablets) in Google Play and other Android app stores by requiring a certain screen size and density in application.xml.

The screenSize attribute refers to how many inches wide the shorter size is:

  • small (approximately 2 to 3 inches)
  • normal (approximately 3 to 5 inches)
  • large (approximately 5 to 7 inches)
  • xlarge (approximately 7 inches or more)

The screenDensity attribute reflects the calculated pixels per inch:

  • ldpi (from 100 to 120 dpi)
  • mdpi (from 120 to 180 dpi)
  • tvdpi (approximately 213 dpi)
  • hdpi (from 180 to 260 dpi)
  • xhdpi (more than 260 dpi)

The following excerpt from application.xml indicates that Rebuild does not support small or low-density screens:

<android> <manifestAdditions><![CDATA[ <manifest android:installLocation="preferExternal"> <supports-screens android:smallScreens="false" android:normalScreens="true" android:largeScreens="true" android:xlargeScreens="true"/> <compatible-screens> <!-- list the screens you support here --> <screen android:screenSize="normal" android:screenDensity="hdpi" /> <screen android:screenSize="normal" android:screenDensity="xhdpi" /> <screen android:screenSize="large" android:screenDensity="ldpi" /> <screen android:screenSize="large" android:screenDensity="mdpi" /> <screen android:screenSize="large" android:screenDensity="hdpi" /> <screen android:screenSize="large" android:screenDensity="xhdpi" /> <screen android:screenSize="xlarge" android:screenDensity="ldpi" /> <screen android:screenSize="xlarge" android:screenDensity="mdpi" /> <screen android:screenSize="xlarge" android:screenDensity="hdpi" /> <screen android:screenSize="xlarge" android:screenDensity="xhdpi" /> </compatible-screens> ... </manifest> ]]></manifestAdditions> </android>

As of early 2012, the most popular Android devices are the Samsung Galaxy phone series (800 x 480), the Motorola Droids (960 x 540), the HTC Evo and Desire (800 x 480), the Samsung Galaxy Tab (1280 x 800), and the Kindle Fire (1024 x 600). However, every country has different popular models and no Android device has a definitive lead on the others, so targeting specific devices is not recommended.

I tested locally using a Nexus One (800x480 released in Jan 2010) which was the low-end of phones I wanted to support, and a Kindle Fire which is an average tablet. As frustrating as slow devices may be, it's better to develop using older hardware so you get a good idea of your minimum performance. Services like TestDroid can help you test remotely on a wider range of devices.

Where to go from here

I put off porting Rebuild to Android for months because I was afraid of handling so many devices, but in the end it was pretty simple to get the scaling in place and only took a few days to get going. I also ported to the BlackBerry PlayBook, which turned out to be well worth the relatively little effort it required.

Adobe AIR makes it easy to run the same code on a thousand different mobile devices. Adobe's done most of the hard work, so if you're planning to target one device, you might as well support all of them in all their different shapes and sizes.


This work is licensed under a Creative Commons Attribution-Noncommercial 3.0 Unported License.

More Like This

  • What's new in Adobe AIR 3
  • Installation and deployment options in Adobe AIR 3
  • Developing cross-platform Adobe AIR applications
  • 10 common mistakes when building Adobe AIR applications
  • Tips for building AIR applications that can be easily updated
  • Adobe AIR and the experience brand
  • Uploading images from CameraRoll and CameraUI
  • Getting started with Adobe AIR for Flex and ActionScript 3 developers
  • Ten tips for building better Adobe AIR applications
  • Deploying Adobe AIR applications seamlessly with badge install

Tutorials and samples

Tutorials

  • Using the iOS Simulator to test and debug AIR applications
  • Using the Amazon In-App Purchase Adobe AIR native extension for Android and Kindle Fire
  • Transferring data with AIR native extensions for iOS – Part 3
  • Exchanging Vector and Array objects between ActionScript 3 and C, C++, or Objective-C

Samples

  • Licensing Adobe AIR applications on Android
  • Using web fonts with Adobe AIR 2.5
  • Using Badger for Adobe AIR applications

AIR blogs

More
07/09/2012 Protected: Publishing Adobe AIR 3.0 for TV on Reference Devices
07/08/2012 Source Code: Adobe AIR 3.3 Retina Video Application
07/06/2012 Application specific File Storage on Adobe AIR based ios Application
07/04/2012 Recent Work - iPad/Android App: Inside My toyota

AIR Cookbooks

More
02/09/2012 Using Camera with a MediaContainer instead of VideoDisplay
01/20/2012 Skinnable Transform Tool
01/18/2012 Recording webcam video & audio in a flv file on local drive
12/12/2011 Date calculations using 'out-of-the-box' functions

Products

  • Acrobat
  • Creative Cloud
  • Creative Suite
  • Digital Marketing Suite
  • Digital Publishing Suite
  • Elements
  • Mobile Apps
  • Photoshop
  • Touch Apps
  • Student and Teacher Editions

Solutions

  • Digital marketing
  • Digital media
  • Web Experience Management

Industries

  • Education
  • Financial services
  • Government

Help

  • Product help centers
  • Orders and returns
  • Downloading and installing
  • My Adobe

Learning

  • Adobe Developer Connection
  • Adobe TV
  • Training and certification
  • Forums
  • Design Center

Ways to buy

  • For personal and home office
  • For students, educators, and staff
  • For small and medium businesses
  • For businesses, schools, and government
  • Special offers

Downloads

  • Adobe Reader
  • Adobe Flash Player
  • Adobe AIR
  • Adobe Shockwave Player

Company

  • News room
  • Partner programs
  • Corporate social responsibility
  • Career opportunities
  • Investor Relations
  • Events
  • Legal
  • Security
  • Contact Adobe
Choose your region United States (Change)
Choose your region Close

North America

Europe, Middle East and Africa

Asia Pacific

  • Canada - English
  • Canada - Français
  • Latinoamérica
  • México
  • United States

South America

  • Brasil
  • Africa - English
  • Österreich - Deutsch
  • Belgium - English
  • Belgique - Français
  • België - Nederlands
  • България
  • Hrvatska
  • Česká republika
  • Danmark
  • Eastern Europe - English
  • Eesti
  • Suomi
  • France
  • Deutschland
  • Magyarország
  • Ireland
  • Israel - English
  • ישראל - עברית
  • Italia
  • Latvija
  • Lietuva
  • Luxembourg - Deutsch
  • Luxembourg - English
  • Luxembourg - Français
  • الشرق الأوسط وشمال أفريقيا - اللغة العربية
  • Middle East and North Africa - English
  • Moyen-Orient et Afrique du Nord - Français
  • Nederland
  • Norge
  • Polska
  • Portugal
  • România
  • Россия
  • Srbija
  • Slovensko
  • Slovenija
  • España
  • Sverige
  • Schweiz - Deutsch
  • Suisse - Français
  • Svizzera - Italiano
  • Türkiye
  • Україна
  • United Kingdom
  • Australia
  • 中国
  • 中國香港特別行政區
  • Hong Kong S.A.R. of China
  • India - English
  • 日本
  • 한국
  • New Zealand
  • 台灣

Southeast Asia

  • Includes Indonesia, Malaysia, Philippines, Singapore, Thailand, and Vietnam - English

Copyright © 2012 Adobe Systems Incorporated. All rights reserved.

Terms of Use | Privacy Policy and Cookies (Updated)

Ad Choices

Reviewed by TRUSTe: site privacy statement