Custom Flex 3 Preloader


Matt - Posted on 23 April 2008

Overview
Unlike Flash movies, the Flex framework provides a preloading graphic free of charge. Whilst useful to give the user some feedback that there's nothing to see until we're fully loaded, most application developers will want to customize this. The preloader is the first screen that anyone will see, and first impressions count so Flex lets us make our own preloader complete with active progress bar.
Luckily for us, the Flex framework displays this preloader right near the beginning of the load routine so the user won't be left with an empty rectangle for very long. It is important, however, to use as few framework classes in your preloader code as possible. When the Flex compiler looks through the application code when it prepares to compile, I believe that any classes used by the preloader are compiled in at the beginning of the SWF. All other classes are placed after the preloader section in the SWF - therefore the less code before the preloader the better as the preloader can't display until all its referenced classes have been loaded from the SWF.
The code here is based on the Flex 2 preloader examples by Ted Patrick. My example is more Flex 3 friendly and removes quite a bit of redundant and confusing code.
Anatomy of the preloader
If you look at the Flex built-in preloader code you'll see it's quite complex. It deals with RSL loading and a whole host of other things. The preloader in this article is quite simple in that it just deals with loading the actual SWF itself. However, you should gain enough understanding to implement your own additional loading functionality if necessary.
There are two main phases that the preloader goes through:
1) Download progress - when the SWF itself is being downloaded from the server.
2) Initialization - after the SWF has fully loaded, the Flex framework initializes the application. During this phase, no progress status is available.
Assigning a preloader to your Application is straightforward. Just use the preloader property of the mx:Application node:
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
preloader="Preloaders.AppPreloader">
The Preloaders.AppPreloader class is our custom class that extends DownloadProgressBar, handles events coming from the framework and tells the framework when we're fully loaded. It also instantiates PreloaderScreen which is our custom class that displays the preloader graphic itself.
Preloaders.AppPreloader
As explained above, the AppPreloader class performs three main tasks:
1) Display the preloader graphic and tell it of any ongoing progress changes
2) Handle framework events pertaining to load progress
3) Tell the framework when we're fully loaded so the application can continue running
The preloader graphic is handled by our other class, Preloaders.PreloaderScreen. AppPreloader just needs to display this graphic, center it and pass it progress updates:
private var preloaderScreen:PreloaderScreen= new PreloaderScreen();
 
public function AppPreloader()
{
super();
 
// Add an event listener so that we can start drawing once we know we're on the stage
addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
}
 
private function onAddedToStage(event:Event):void {
 
// Add the loader screen to the stage and center it
addChild(preloaderScreen);
preloaderScreen.x = (stage.stageWidth-preloaderScreen.width)/2;
preloaderScreen.y = (stage.stageHeight-preloaderScreen.height)/2;
 
// Force an initial draw of the screen
preloaderScreen.refreshDisplay();
}
Note that we only display the graphic once we're added to the stage - otherwise we won't be able to get a stage width and height to center the graphic by.
Handling the framework events is easy - our base class hands us the preloader instance via the "set preloader" overridden method. At this point we need to add event listeners for two events:
1) ProgressEvent.PROGRESS - alerts us periodically when more content is loaded via the download phase
2) FlexEvent.INIT_COMPLETE - lets us know that the initialization phase is complete
// Called by the framework so we can add our event listeners to the various events we're interested in
override public function set preloader(value:Sprite):void {
value.addEventListener(ProgressEvent.PROGRESS, progressEventHandler);
value.addEventListener(FlexEvent.INIT_COMPLETE, initCompleteEventHandler);
}
Beyond that we just need to update the PreoloaderScreen of our progress:
// We've made progress... tell the screen the new progress value
private function progressEventHandler(event:ProgressEvent):void {
preloaderScreen.progress = event.bytesLoaded/event.bytesTotal;
}
and alert the framework that we're ready to continue with the application after our preloader is complete:
// Load complete, fire the Event.COMPLETE event and the framework will carry on from there
private function initCompleteEventHandler(event:FlexEvent):void {
dispatchEvent(new Event(Event.COMPLETE));
}
Preloaders.PreloaderScreen
The PreloaderScreen class deals with the actual graphical part of the preloader. In this example case we have a background image (as a PNG file) and the progress bar which consists of a grey background area with a green bar that increase in width until the background is full. As mentioned above, it's important that we use as few classes as possible so all drawing is done directly via the graphics context into a BitmapData. We don't use any Flex components to avoid loading in the entire UI system before we can show our preloader.
When AppPreloader wants us to redisplay, it calls either the public refreshDisplay method or changes the progress value which in turn calls refreshDisplay:
// Number between 0 and 1 indicating how far through the loading progress we are
public function set progress(n:Number):void { _progress = n; refreshDisplay(); }
public function get progress():Number { return _progress; }
The refreshDisplay method gets our drawn BitmapData, encodes it into a PNG then loads this PNG onto itself (PreloaderScreen extends Loader so we can do this easily):
// Called to get the screen graphic and display
public function refreshDisplay():void {
var bmpData:BitmapData = drawProgress();
var encoder:PNGEncoder = new PNGEncoder();
var byteArray:ByteArray = encoder.encode(bmpData);
this.loadBytes(byteArray);
}
drawProgress is the method that does all the hard work here. it involves direct drawing of graphical elements onto the BitmapData. This is fast and uses few external classes so is very efficient for our use: I won't include the code here, feel free to download the source code at the end of this article.
The finished product
Note that you'll have to refresh this page to see the preloader from the beginning! You can download the full source below.

<!--[if gte IE 7]>-->

<!--<![endif]-->
Sorry, flash is not available.
<!--[if gte IE 7]>-->

<!--<![endif]-->

AttachmentSize
preloader.zip1.2 MB

thanks ,
i found this nice looking preloader over here on this article , would like to share with flex guys :
http://askmeflash.com/article_m.php?p=article&id=7

Thanks for the link. The code looks good, although I'd hesitate to use a millisecond timer when you get periodic progress events sent to you from the framework.

I have been looking for a good pre-loader -- I'm tired of the default one and would like to do some branding at the same time. I like the way this one looks!

I'd lke to use this in an external class library. Can the PreloaderScreen be modified to accept different background images rather than embed a default? Something like preloader="Preloaders.AppPreloader('assets/myimage.png') " This way it could be used for many different brands.

I'm guessing this one is much lighter than the stock one and should go faster?

Thanks!

nais one m8,

how did you get rid of the standard color page just before the preloader
kicks in?
the swf on this page has'nt got it but the source example has got the
short blink of this page

cheers, david

ok(at)tiscali(dot)nl

It may be the default color of the movie as specified in the PARAM tags of the HTML object:

That makes the control color white immediately and before it even starts loading the SWF.

...you forgot the "end of the article" as in "feel free to download the source code at the end of this article." :)

Since I'm in a bit of a hurry, I'll probably copy/paste those bits and hope you mentioned enough to complete it, but you could update the post to include the source! :)

I'm an idiot! Forgot to set download permissions for visiting readers. It's all there for download now!

Sorry about that ;)

About the author

Matthew Butt is an experienced developer, software architect and development manager. For more information, review the About page.