Source Code and Comments

We have offered several tutorials in the past (see the list at the end) to explain how to import external SWF files, but our latest project has led us to revisit this topic in the context of mobile apps. In particular we'd like to accomplish a few specific things to deliver a scrollable "help file" in the form of an external SWF:

  • We'd like to load an external SWF file, but we'd like that file to be packaged with the mobile app so that Internet access is not required.
  • Since we'd like to have a large number of help files, it is important that these open and close in a way that does not cause the memory demands to increase steadily while the app is running.
  • Once the SWF is open, it should have a normal, simple scrolling interface.
  • All of this should be packaged in resusable, custom classes.

The custom AS3 classes and source files presented below accomplish our goals.

Download

The package contains SWFScroller.as, SWFScrollerEvent.as, ScrollDemo.fla and SampleText.swf. It also contains InfoMobile.as (our simple stats class), and a few screen shots.

The SampleText.swf, included in the download zip file, was created in a separate fla file with no script. The file consists of a large background rectangle and graphics and static textboxes containing the instructions. To call the constructor for the SWFScroller class, you will need to know the dimensions of the external SWF file.

You can use ScrollDemo.fla in Flash CS5.5 or in Flash CS5. In Flash CS5, you have to have AIR for Android Extension installed.

AIR Android Settings

In setting up the ScrollDemo.fla file for publishing to your Android phone, you will see the options below. Clicking the "+" symbol above "Included Files" allows you to add as many external SWF's as you would like. The SWFScroller class uses a Loader object to load at runtime any of the included swf files without requiring Internet connectivity.

Publish Settings

The custom SWFScroller class

package {

// import statements
:

public class SWFScroller extends Sprite {

private var bd:BitmapData;

private var bitmap:Bitmap;

 

private var responsiveness:Number;

 

private var myLoader:Loader;

private var url:URLRequest;

 

private var newY:Number;

private var origY:Number;

 

private var bdWidth:Number;

private var bdHeight:Number;

 

private var cWidth:Number;

private var cHeight:Number;

private var cColor:uint;

 

private var container:Sprite;

 

private var spClose:Sprite;

private var txtClose:TextField;

 

private var sEvt:SWFScrollerEvent;

 

public function SWFScroller(bw:Number,bh:Number,stURL:String) {

responsiveness = 0.2;

 

container = new Sprite();

container.x = 0;

container.y = 0;

this.addChild(container);

 

cHeight = 80;

cWidth = 480;

cColor = 0x009900;

 

spClose = new Sprite();

drawClosedButton();

 

spClose.addEventListener(MouseEvent.CLICK, closeMe);

spClose.visible = false;

this.addChild(spClose);

 

bdWidth = bw;

bdHeight = bh;

bd = new BitmapData(bdWidth, bdHeight, false, 0);

bitmap = new Bitmap(bd);

 

url = new URLRequest(stURL);

myLoader = new Loader();

myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, loader_complete);

myLoader.load(url);

}

 

private function closeMe(me:MouseEvent):void {

// We do a lot of cleanup to maximize performance.

spClose.removeEventListener(MouseEvent.CLICK, closeMe);

stage.removeEventListener(MouseEvent.MOUSE_DOWN, onDown);

stage.removeEventListener(Event.ENTER_FRAME, dragging);

 

this.removeChild(spClose);

container.removeChild(bitmap);

this.removeChild(container);

 

myLoader.unload();

myLoader = null;

spClose = null;

bitmap = null;

container = null;

 

// Suggest to the system that it start garbage collection. This line keeps memory usage fairly constant regardless of how many times the user opens and closes the help file.

System.gc();

 

// Dispatch the CLOSED event from the custom class SWFScrollerEvent so the calling movie can "clean up" after the scroller is closed.

sEvt = new SWFScrollerEvent("closed");

dispatchEvent(sEvt);

}

The loader_complete function takes the content from myLoader cast as a MovieClip and draws it in a bitmap object. This process improves performance (evidenced by memory load and maintaining constant framerate) over simply adding the loader content as a child of the container directly.

private function loader_complete(evt:Event):void {

var mc:MovieClip = myLoader.content as MovieClip;

bd.draw(mc);

container.addChild(bitmap);

 

stage.addEventListener(MouseEvent.MOUSE_DOWN, onDown);

stage.addEventListener(Event.ENTER_FRAME, dragging);

 

myLoader.contentLoaderInfo.removeEventListener(Event.COMPLETE, loader_complete);

}

 

private function onDown(e:MouseEvent):void {

// Measure offset of initial screen touch relative to position on container

origY = container.y;

newY = e.stageY;

spClose.visible = true;

spClose.x = 0;

spClose.y = stage.stageHeight - cHeight;

}

 

private function dragging(e:Event):void {

// Get stage position of mouse (finger) converted to relative position on the scrollable object

var nextY:Number = stage.mouseY + (origY - newY);

 

// If change in position is small, then stop motion altogether.

if (Math.abs(nextY - container.y) < 10) return;

 

// Tween-like movement toward the last position of the finger on the screen

container.y = container.y + responsiveness*(nextY - container.y);

 

// Control highest and lowest possible position

if (container.y > 0) container.y = 0;

if (container.y < -2000) container.y = -2000;

}

 

// Function to draw the CLOSED button

private function drawClosedButton():void {

var tf:TextFormat = new TextFormat("_sans", cHeight/2,0x000000,true);

tf.align = "center";

 

spClose.graphics.clear();

spClose.graphics.lineStyle(0,0);

spClose.graphics.beginFill(cColor,0.9);

spClose.graphics.drawRect(0,0,cWidth,cHeight);

spClose.graphics.endFill();


txtClose = new TextField();

txtClose.height = 3/4*cHeight;

txtClose.width = cWidth - 10;

txtClose.x = 5;

txtClose.y = cHeight/8;

txtClose.mouseEnabled = false;

txtClose.defaultTextFormat = tf;

txtClose.text = "TAP TO CLOSE";

spClose.addChild(txtClose);

}

 

// Getter/setters to control the dimensions & color of the CLOSED button

public function get closeWidth():Number {

:

}

public function set closeWidth(n:Number):void {

:

}

public function get closeHeight():Number {

:

}

public function set closeHeight(n:Number):void {

:

}

public function get closeColor():uint {

:

}

public function set closeColor(c:uint):void {

:

}

 

// Getter/setter for "responsiveness" variable

public function get responseNumber():Number {

:

}

public function set responseNumber(r:Number):void {

:

}

}

}

SWFScroller class calls the custom class SWFScrollerEvent class. This simple class (contained in the zip package) extends the standard Event class, adding only a "closed" event that is dispatched when an SWFScroller object is closed.

The Code for the Main Movie, scrollerDemo.fla

stage.scaleMode = StageScaleMode.NO_SCALE;

stage.align = StageAlign.TOP_LEFT;

 

var s:SWFScroller;

 

// InfoMobile class displays memory use and frame size. Comment out to hide.

var inf:InfoMobile = new InfoMobile();

inf.x = 2;

inf.y = 2;

addChild(inf);

 

btnHelp.addEventListener(MouseEvent.CLICK, openHelp);

 

function openHelp(me:MouseEvent):void {

s = new SWFScroller(480,2800,"SampleText.swf");

btnHelp.visible = false;

 

// Start listening for the custom CLOSED event so we

// can remove listeners and children when the SWFScroller

// object is closed.

 

s.addEventListener(SWFScrollerEvent.CLOSED, closed);

addChild(s);

 

// Adjust index of InfoMobile object to keep it on top.

// Comment out this line if you are not using the InfoMobile object.

 

setChildIndex(inf,numChildren - 1);

}

 

function closed(se:SWFScrollerEvent):void {

// Remove listener & children to minimize memory usage

s.removeEventListener(SWFScrollerEvent.CLOSED, closed);

removeChild(s);

s = null;

btnHelp.visible = true;

}

 

btnClose.addEventListener(MouseEvent.CLICK, quit);

 

function quit(me:MouseEvent):void {

NativeApplication.nativeApplication.exit(0);

}

External SWF versus StageWebView

An alternative way of displaying help files is provided by the mobile AIR's StageWebView class. See our tutorial: Display Web Content within AIR Mobile App - StageWebView Tutorial. The tradeoff is that loading remote HTML files into an instance of StageWebView requires an Internet connection. If HTML files are local, they have to be limited to text as StageWebView will not load local assets like images.

Related Flash and Math Tutorials

Loading external SWFs:

For smooth dragging:

StageWebView:

Mobile performance:

Drawing into a BitmapData object:

This Flash and Math AIR for Mobile Tutorial is related to Mobile Math Apps project by Doug Ensley and Barbara Kaskosz.

Back to AIR for Mobile              Back to Flash and Math Home

We welcome your comments, suggestions, and contributions. Click the Contact Us link below and email one of us.

Adobe®, Flash®, ActionScript®, Flex® are registered trademarks of Adobe Systems Incorporated.