Custom Flex Preloaders : Part Three Finally we’re playing with Flex
OK – so check out Part Two for see the flash assets we’ve produced and download them from here if you need them – > Basic Flash Assets.
Now we want to create a new flex project. Open flex and create a new project, call it whatever you feel like and click on finish.
Create an assets folder, and in the assets folder create a swf folder (where we’ll pop the preloader swf) and I’ve created an originals folder to put some images that we will use to bloat the flex file so we can have a decent file size to test the preloaders are working.
To hold the code I’ve created a com/worthyashes/preloaders folder. This is a standard way of creating a namespace for your code so it won’t conflict with any other code that you may be using in the project. I also create an archive folder – this is just something I do to hold bits and is not necessary for this to work.
Save the swf to the assets/swf folder and we are ready to go.
First off we need to bloat the file so we’ve got something to work with.
BasicCustomPreloader.mxml : -
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
preloader="com.worthyashes.preloaders.BasicCustomPreloader"
layout="vertical">
<mx:Script>
<![CDATA[
/*
Here are some images to bloat up the size of the swf
*/
import mx.events.FlexEvent;
[Bindable]
[Embed(source="assets/originals/bush.jpg")]
private var img1:Class;
[Embed(source="assets/originals/charlieHavingBreakfast.jpg")]
private var img2:Class;
[Embed(source="assets/originals/field1.jpg")]
private var img3:Class;
[Embed(source="assets/originals/field2.jpg")]
private var img4:Class;
[Embed(source="assets/originals/frostyHedge.jpg")]
private var img5:Class;
[Embed(source="assets/originals/frozenBranches.jpg")]
private var img6:Class;
[Embed(source="assets/originals/gardenSteps1.jpg")]
private var img7:Class;
[Embed(source="assets/originals/gardenSteps2.jpg")]
private var img8:Class;
]]>
</mx:Script>
<!--We'll display an image so we can prove it initialised properly-->
<mx:Image source="{img1}" width="100%" height="100%" horizontalAlign="center"/>
</mx:Application>
Using the Embed keyword we are telling the compiler to add these files to the swf, not load them at runtime. Normally you wouldn’t want to do this but it’s perfect for us as we want to have a large swf. This has pushed the swf size up to just over 10Meg. Perfect. The last thing we do is display one of the images so we have a visual cue that the application has loaded.
The line in the Application tag
preloader=”com.worthyashes.preloaders.BasicCustomPreloader”
Tells the application to ignore the standard preloader and load our Custom Preloader class instead.
Now for the preloader code. I’ll reproduce it here and then we’ll go through it.
BasicCustomPreloader.as
package com.worthyashes.preloaders
{
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.ProgressEvent;
import mx.events.FlexEvent;
import mx.preloaders.DownloadProgressBar;
public class BasicCustomPreloader extends DownloadProgressBar
{
private var preloadMovieClip:MovieClip;
[Embed(source="assets/swf/basic.swf",symbol="preloader")]
private var PreloaderAssets:Class;
public function BasicCustomPreloader()
{
super();
preloadMovieClip = new PreloaderAssets();
addChild(preloadMovieClip);
}
//This is the most important
override public function set preloader(preloader:Sprite):void
{
preloader.addEventListener(ProgressEvent.PROGRESS,downloadProgress);
preloader.addEventListener(Event.COMPLETE,downloadComplete);
preloader.addEventListener(FlexEvent.INIT_PROGRESS,flexInitProgress);
preloader.addEventListener(FlexEvent.INIT_COMPLETE,flexInitComplete);
preloadStarted();
}
private function preloadStarted():void
{
centreClip();
}
private function centreClip():void
{
x = (stageWidth/2) - (preloadMovieClip.width/2);
y = (stageHeight/2) - (preloadMovieClip.height/2);
}
private function downloadProgress(event:ProgressEvent):void
{
var percentage:int = Math.round(event.bytesLoaded/event.bytesTotal*100)
preloadMovieClip.percent_txt.text = percentage.toString() + "%";
}
private function downloadComplete(event:Event):void
{
preloadMovieClip.percent_txt.text = "100%";
}
private function flexInitProgress(event:FlexEvent):void
{
preloadMovieClip.percent_txt.text = "Initialising";
}
private function flexInitComplete(event:FlexEvent):void
{
dispatchEvent(new Event(Event.COMPLETE));
}
}
}
We’d better go through the code.
First of all, as we discussed in Part One, we are extending the DownloadProgressBar class. This class has all of the functionality for handling the loading and initialising of the application, so we don’t have to worry about that.
Next we have a variable to hold our MovieClip that we will use as the preloader.
private var preloadMovieClip:MovieClip;
And we will embed the swf.
[Embed(source="assets/swf/basic.swf",symbol="preloader")]
private var PreloaderAssets:Class;
The swf needs to be embedded as a generic Class, but we have a second attribute in the Embed metadata which has a reference to the symbol we are going to use. This is given the same name as the Linkage name we gave the symbol in the flash movie. So we now have access to the preloader movieclip.
In the constructor we can tie these two variables together.
public function BasicCustomPreloader()
{
super();
preloadMovieClip = new PreloaderAssets();
addChild(preloadMovieClip);
}
This bit of code sets up the preloadMovieClip variable as a new instance of the preloader movieclip from the embeded swf file. Now we can use dot notation to access anything within this clip.
Next we override the set preloader function from the DownloadProgressBar Class. We set up four event listeners to handle the download progress and the initialisation of the application.
override public function set preloader(preloader:Sprite):void
{
preloader.addEventListener(ProgressEvent.PROGRESS,downloadProgress);
preloader.addEventListener(Event.COMPLETE,downloadComplete);
preloader.addEventListener(FlexEvent.INIT_PROGRESS,flexInitProgress);
preloader.addEventListener(FlexEvent.INIT_COMPLETE,flexInitComplete);
preloadStarted();
}
These are mapped to further functions which will actually do the work for the preloader. The preloadStarted function is called to do any initial work required for the preloader, in our case making sure the preloader is displayed in the centre of the screen. (I won’t go through that code, it’s very straight-forward)
Lets look at the listeners
private function downloadProgress(event:ProgressEvent):void
{
var percentage:int = Math.round(event.bytesLoaded/event.bytesTotal*100)
preloadMovieClip.percent_txt.text = percentage.toString() + “%”;
}
The downloadProgress function works out the percentage loaded and then displays the result in the percent_txt dynamic text field that lives in the preload movieclip in the swf. As you can see we can get to this text field using the preloadMovieClip variable we set up earlier and dot notation.
private function downloadComplete(event:Event):void
{
preloadMovieClip.percent_txt.text = “100%”;
}
When the download is complete we can simply set it to 100%. However this isn’t the end of the preload process as we now need to wait for the application to build itself and initialise.
private function flexInitProgress(event:FlexEvent):void
{
preloadMovieClip.percent_txt.text = “Initialising”;
}
Once the download is complete we need to display some sort of indicator that the application is starting. In this case I made it quite simple and just changed the text in the percent_txt text field.
private function flexInitComplete(event:FlexEvent):void
{
dispatchEvent(new Event(Event.COMPLETE));
}
Once the application is fully downloaded and initialised we need to dispatch a COMPLETE event. As we’ve overridden the existing function in the DownloadProgressBar it will not automatically dispatch this event and we need to do it ourselves.
You can see the working preloader here.
Next lets tidy up the code and have a bit of fun.
