Beginning ActionScript 2.0 2006
.pdfChapter 8
Here’s an example implementation that loads an external movie clip called section1.swf into a movie clip called sectionHolder:
this.createEmptyMovieClip(“sectionHolder”, this.getNextHighestDepth());
var loadListener:Object = new Object(); loadListener.onLoadComplete = function(contentHolder:MovieClip)
{
trace(“Content has been loaded”);
};
var contentLoader:MovieClipLoader = new MovieClipLoader(); contentLoader.addListener(loadListener); contentLoader.loadClip(“section1.swf”, sectionHolder);
removeListener()
The removeListener() method is used to break the binding between the event handlers and the pre-loader. It takes one parameter, which is the handle to the listener object that was initially passed in to the addListener() method. The following prototype shows the basic form of the removeListener() method:
loaderObject.removeListener(listener:Object) : Boolean
If, for example, you want to hold up playback until enough of the movie has downloaded to ensure that playback is not impeded by network delays, you could handle it like the following example, which removes the listener and starts playback after 50% of the movie has downloaded:
this.createEmptyMovieClip(“sectionHolder”, this.getNextHighestDepth());
var loadListener:Object = new Object(); loadListener.onLoadProgress = function(contentHolder:MovieClip, ;
bytesLoaded:Number, bytesTotal:Number)
{
var percentDone:Number = bytesLoaded / bytesTotal * 100; if (percentDone > 50)
{
contentHolder.play();
contentLoader.removeListener(this);
}
};
var contentLoader:MovieClipLoader = new MovieClipLoader(); contentLoader.addListener(loadListener); contentLoader.loadClip(“section1.swf”, sectionHolder);
unloadClip()
Media should be properly unloaded from the movie clip before another clip is loaded. The unloadClip() method takes one parameter, which is a handle to the movie clip containing the loaded media. The following prototype shows the basic form of the unloadClip() method:
loaderObject.unloadClip(target:Object) : Boolean
208
Pre-Loading Movies
The following example shows how you can unload a movie clip:
this.createEmptyMovieClip(“sectionHolder”, this.getNextHighestDepth());
var contentLoader:MovieClipLoader = new MovieClipLoader(); contentLoader.loadClip(“section1.swf”, sectionHolder);
cancelButton.onRelease = function()
{
contentLoader.unloadClip(sectionHolder);
};
Implementing the MovieClipLoader Class
With an understanding of the MovieClipLoader class, you’re ready to put it into action. First, put together a shell for the event handlers and tie that in to a new loader instance:
this.createEmptyMovieClip(“sectionHolder”, this.getNextHighestDepth());
var loadListener:Object = new Object(); loadListener.onLoadStart = function(contentHolder:MovieClip)
{
};
loadListener.onLoadProgress = function(contentHolder:MovieClip, ; bytesLoaded:Number, bytesTotal:Number)
{
};
loadListener.onLoadComplete = function(contentHolder:MovieClip)
{
};
var contentLoader:MovieClipLoader = new MovieClipLoader(); contentLoader.addListener(loadListener); contentLoader.loadClip(“http://www.nathanderksen.com/book/trailer.swf”, ;
sectionHolder);
Here, an empty object is created, and one method is added for each event to be handled. Not all events have to be handled, just the ones that you need. A new instance of the loader class is created and is bound to this object. Finally, the clip is loaded into the container movie clip. At this point you have a working pre-loader; it just does not call anything yet before, during, or after loading.
Each of these code snippets is available in the downloadable content for this book. Feel free to experiment with each snippet.
Like the custom loader created previously, you still need to provide visual feedback for the user. Add the shell code for this:
this.createEmptyMovieClip(“sectionHolder”, this.getNextHighestDepth()); this.createEmptyMovieClip(“progressMovie”, this.getNextHighestDepth()); progressMovie._x = 60;
progressMovie._y = 120;
209
Chapter 8
progressMovie.createTextField(“percentDoneLabel”,
progressMovie.getNextHighestDepth(), 40, 0, 100, 20);
var loadListener:Object = new Object(); loadListener.onLoadStart = function(contentHolder:MovieClip)
{
};
loadListener.onLoadProgress = function(contentHolder:MovieClip, ; bytesLoaded:Number, bytesTotal:Number)
{
};
loadListener.onLoadComplete = function(contentHolder:MovieClip)
{
};
var contentLoader:MovieClipLoader = new MovieClipLoader(); contentLoader.addListener(loadListener); contentLoader.loadClip(“http://www.nathanderksen.com/book/trailer.swf”, ;
sectionHolder);
function showProgress(percentDone:Number, progressBarHolder:MovieClip) : Void
{
var barWidth:Number = percentDone;
progressBarHolder.percentDoneLabel.text = String(Math.ceil(percentDone))+” %”; progressBarHolder.clear();
//Draw a border progressBarHolder.moveTo(0, 20); progressBarHolder.lineStyle(1, 0x666666); progressBarHolder.lineTo(100, 20); progressBarHolder.lineTo(100, 30); progressBarHolder.lineTo(0, 30); progressBarHolder.lineTo(0, 20);
//Draw the bar progressBarHolder.moveTo(0, 20); progressBarHolder.beginFill(0xCCCCCC, 100); progressBarHolder.lineTo(barWidth, 20); progressBarHolder.lineTo(barWidth, 30); progressBarHolder.lineTo(0, 30); progressBarHolder.lineTo(0, 20); progressBarHolder.endFill();
}
As before, a movie clip holds the progress bar and the percent progress text field, and the showProgress() function draws the progress bar and updates the percent progress value.
Finally, you need to fill out the event handlers:
this.createEmptyMovieClip(“sectionHolder”, this.getNextHighestDepth()); this.createEmptyMovieClip(“progressMovie”, this.getNextHighestDepth()); progressMovie._x = 60;
210
Pre-Loading Movies
progressMovie._y = 120; progressMovie.createTextField(“percentDoneLabel”, progressMovie.getNextHighestDepth(), 40, 0, 100, 20);
var loadListener:Object = new Object(); loadListener.onLoadStart = function(contentHolder:MovieClip)
{
progressMovie._visible = true; contentHolder._visible = false; contentHolder.stop();
};
loadListener.onLoadProgress = function(contentHolder:MovieClip, ; bytesLoaded:Number, bytesTotal:Number)
{
var percentDone:Number = bytesLoaded / bytesTotal * 100;
showProgress(percentDone, progressMovie);
};
loadListener.onLoadComplete = function(contentHolder:MovieClip)
{
progressMovie._visible = false; contentHolder._visible = true; contentHolder.play();
};
var contentLoader:MovieClipLoader = new MovieClipLoader(); contentLoader.addListener(loadListener); contentLoader.loadClip(“http://www.nathanderksen.com/book/trailer.swf”, ;
sectionHolder);
function showProgress(percentDone:Number, progressBarHolder:MovieClip) : Void
{
var barWidth:Number = percentDone;
progressBarHolder.percentDoneLabel.text = String(Math.ceil(percentDone))+” %”; progressBarHolder.clear();
//Draw a border progressBarHolder.moveTo(0, 20); progressBarHolder.lineStyle(1, 0x666666); progressBarHolder.lineTo(100, 20); progressBarHolder.lineTo(100, 30); progressBarHolder.lineTo(0, 30); progressBarHolder.lineTo(0, 20);
//Draw the bar progressBarHolder.moveTo(0, 20); progressBarHolder.beginFill(0xCCCCCC, 100); progressBarHolder.lineTo(barWidth, 20); progressBarHolder.lineTo(barWidth, 30); progressBarHolder.lineTo(0, 30); progressBarHolder.lineTo(0, 20); progressBarHolder.endFill();
}
211
Chapter 8
The custom loader created earlier had no designated spot to put initialization code and required a manual test to see if the bytesLoaded() method returned zero. The MovieClipLoader class gives you an onLoadStart event that is a good place for initialization code, and the class deals with some of the intricacies of load startup so that you do not have to.
A good thing to add to this code is an onLoadError event handler. This handler provides a graceful response to an incorrect URL or an interrupted transfer. You have an opportunity to add this event handler in an end-of-chapter exercise.
Examining the Loader and ProgressBar
Components
One of the tradeoffs with using a pre-existing component versus one created from scratch is that there is a balance between complexity and control. Your homemade pre-loader is definitely the most flexible, but also requires the most work. The MovieClipLoader class takes control over how the polling process works during the load, but it makes up for it in reusability. The Loader and ProgressBar components do the most to take over the work of implementing loader code and implementing visual feedback drawing code, but using them restricts you to the features provided by the components.
One drawback to the Loader and ProgressBar components is that they cause Flash to compile the whole component framework into the movie you are creating. The framework together with the two components results in around 32 kilobytes of additional file size that needs to be loaded. This makes these components unsuitable for the initial loading of content, because it takes a while before the progress status makes it to the screen. Instead, these components work better for situations where you need to load chunks of content in a piecemeal fashion after the main content has loaded.
Before going into how to implement the Loader and ProgressBar components, take a look at their properties, methods, and events.
Loader Component Method, Properties, and Events
The Loader component is a container to load content into, and it can hold either an .swf file or a .jpg file. With version 8 of the Flash player, it also supports .gif and .png files, including those with transparency. Whereas the MovieClipLoader class requires a movie clip to be provided, the Loader component comes with its own movie clip.
There’s only one Loader method, load(), which triggers the start of the load process. It takes either no argument or one single argument. If no argument is given, the contentPath property must have been specified beforehand. If one argument is given, it is a string representing the path to the content to be loaded. load() returns nothing. The following prototype shows the basic form of the load() method:
loaderInstance.load([contentPath:String]) : Void
If the autoLoad property is set to true, then setting the contentPath property automatically triggers the load, making the load() method unnecessary.
212
Pre-Loading Movies
Following is a delineation of the component’s properties:
|
Property |
Type |
Description |
|
|
|
|
|
|
|
|
|
|
|
|
autoLoad |
Boolean |
If true, content loads immediately upon setting the content |
|
|
|
|
Path property. If false, the loader waits for a load() call. |
|
|
bytesLoaded |
Number |
The total number of bytes loaded. (Read only.) |
|
|
bytesTotal |
Number |
The total number of bytes for the content. (Read only.) |
|
|
content |
MovieClip |
A handle to the movie clip holding the content. (Read |
|
|
|
|
only.) |
|
|
contentPath |
String |
The path to the loaded content. |
|
|
percentLoaded |
Number |
The percentage of the content already loaded. (Read only.) |
|
|
scaleContent |
Boolean |
If true, content scales to fit the size of the loader. If false, |
|
|
|
|
content is not scaled and the loader size adjusts to fit. |
|
|
|
|
|
|
The Loader component has two events, described in the following table.
Event |
Type |
Description |
|
|
|
complete |
Listener |
Fires when the content has finished loading. |
progress |
Listener |
Fires repeatedly during the load process. |
ProgressBar Component Method, Properties, and Events
The ProgressBar component works alongside the Loader component to provide visual feedback of the media load progress. This component has only one method: setProgress(). The setProgress() method is for setting the progress values manually, and works only when the mode property is set to manual. It takes two arguments: first, a value for the total amount loaded and, second, a value for the total to load. The following prototype shows the basic form of the setProgress() method:
progressBarInstance.setProgress(completed:Number, total:Number) : Void
You can use the progress bar in manual mode for purposes other than recording bytes loaded. It can, for example, show a progression of number of files loaded where completed represents the number of files loaded and total indicates the total number of files to load.
The ProgressBar component’s properties are described in the following table.
213
Chapter 8
Property |
Type |
Description |
|
|
|
conversion |
Number |
Conversion factor for converting bytes loaded into another |
|
|
unit for display purposes. Using a value of 1024 converts |
|
|
bytes loaded into kilobytes loaded. |
direction |
String |
The direction that the progress bar advances. Values available |
|
|
are left and right. |
indeterminate |
Boolean |
If true, an animated striped fill is used instead of a solid fill. |
|
|
Used when loading content of unknown size. If false, the |
|
|
progress bar advances normally. |
label |
String |
The text to use to indicate loading progress. The text can |
|
|
include the key strings %1, %2, %3, and %%. The first is a place- |
|
|
holder for bytes loaded, the second is for total bytes, the third |
|
|
is for percent loaded, and the final is to show a percent |
|
|
symbol. A sample label is %1 out of %2 bytes loaded, |
|
|
%3%% complete. |
labelPlacement |
String |
Sets the position of the label relative to the progress bar. |
|
|
Possible values are left, right, top, bottom, and center. |
maximum |
Number |
Holds the largest progress value for when the mode property |
|
|
is set to manual. |
minimum |
Number |
Holds the smallest progress value for when the mode property |
|
|
is set to manual. |
mode |
String |
Controls how progress deals with loaded content. Possible |
|
|
values are event, polled, and manual. The value event is |
|
|
for working with the Loader component, polled is for working |
|
|
with movie clips, and manual is for manual setting the progress. |
percentComplete |
Number |
Indicates the percentage of the content that has been loaded. |
|
|
(Read only.) |
source |
Object |
A source of progress information. Can be a Loader component |
|
|
or a movie clip. |
value |
Number |
Indicates the progress that has been made between the mini- |
|
|
mum and maximum properties when the mode property is set |
|
|
to manual. |
The following table delineates the ProgressBar component’s two events:
Event |
Type |
Description |
|
|
|
complete |
Listener |
Fires when the content has finished loading. |
progress |
Listener |
Fires repeatedly during the load process. |
214
Pre-Loading Movies
Implementing the Loader and ProgressBar Components
Unlike a class, which is either available directly from the player or is compiled into the .swf by design, components are not automatically included in the compile. You can call the code to create a new instance on the stage, but if the component isn’t in the library, it won’t appear on the stage. You have two ways to place a copy of a component in the library:
Drag one of each component needed from the Components panel onto the stage and then delete each one from the stage. Dragging a component to the stage automatically places the component in the library. This is the standard approach in the Flash MX 2004 authoring environment.
In the Flash 8 authoring environment, drag each component needed from the Components panel onto the Library panel.
With that done, you can create instances of the two components:
this.createClassObject(mx.controls.Loader, “loaderComponent”, ; this.getNextHighestDepth());
this.createClassObject(mx.controls.ProgressBar, “progressComponent”, ;
this.getNextHighestDepth()); progressComponent._x = 50; progressComponent._y = 100;
This code creates an instance of the Loader component and of the ProgressBar component and places them on the stage with the instance IDs loaderComponent and progressComponent. It also positions the progress bar so that it will show in the middle of the loader component. The createClassObject() method enables you to place any component on the stage programmatically instead of having to manually place each instance on the stage. This method is described in more detail in Chapter 9.
Next, you place the code to actually work with these components. By setting the source property of the progress bar to point to loaderComponent, the two are linked and the progress bar automatically reflects the status of the loader component:
this.createClassObject(mx.controls.Loader, “loaderComponent”, ; this.getNextHighestDepth());
this.createClassObject(mx.controls.ProgressBar, “progressComponent”, ; this.getNextHighestDepth());
progressComponent._x = 50; progressComponent._y = 100;
progressComponent.source = loaderComponent; loaderComponent.scaleContent = false; loaderComponent.load(“http://www.nathanderksen.com/book/trailer.swf”);
Now you have a working progress bar. The source property links up the loader as a source of progress information for the bar to use. The scaleContent property makes sure that the content does not scale to the size of the Loader component; instead, the component resizes itself to accommodate whatever dimensions the content ends up having.
A couple of issues remain. First, the content starts playing before loading is done, and second, the progress bar stays around after loading is complete. These can be dealt with by adding a couple of event listeners:
215
Chapter 8
this.createClassObject(mx.controls.Loader, “loaderComponent”, ; this.getNextHighestDepth());
this.createClassObject(mx.controls.ProgressBar, “progressComponent”, ; this.getNextHighestDepth());
progressComponent._x = 50; progressComponent._y = 100;
var loadHandler:Object = new Object(); loadHandler.progress = function(eventObject:Object)
{
loaderComponent.content.stop();
}
loadHandler.complete = function(eventObject:Object)
{
loaderComponent.content.play(); progressComponent._visible = false;
}
progressComponent.source = loaderComponent; loaderComponent.scaleContent = false; loaderComponent.addEventListener(“progress”, loadHandler);
loaderComponent.addEventListener(“complete”, loadHandler); loaderComponent.load(“http://www.nathanderksen.com/book/trailer.swf”);
Here, two events are defined and then bound to the Loader instance. Unfortunately the Loader component only provides a progress event and a complete event. As a result, the initialization code to stop the playback of the loaded movie clip until it is complete has to go into the progress event handler. This means that the initialization code is called many times when it only needs to be called once, but that’s not enough to hamper performance.
Note the amount of code that is needed to implement the Loader and ProgressBar components versus the MovieClipLoader class and versus our homegrown loader. The homegrown loader code took around 43 lines of code to implement, the MovieClipLoader class took roughly 38 lines of code, and the component implementation took about 15 lines of code. Most of this savings in code from using the components comes from replacing the drawing function with two lines of code to use the ProgressBar component. This component can also work with the MovieClipLoader class, as you see in the exercises at the end of this chapter.
One frequent question that developers ask is how to customize the appearance of the Loader component. The setStyle() method that is available for any component provides a capability to customize aspects of component appearance. The following snippet shows how the text color, text size, and progress bar color properties can be changed:
progressComponent.setStyle(“color”, 0x0000CC); progressComponent.setStyle(“fontSize”, 14); progressComponent.setStyle(“themeColor”, 0xCC0000);
The styles that can be changed for the Loader component are described in the following table.
216
|
|
|
Pre-Loading Movies |
|
|
|
|
|
Style |
Type |
Description |
|
|
|
|
|
themeColor |
String or |
Color to use for component accents, in this case the color |
|
|
Number |
for the progress bar itself. Possible values are haloGreen, |
|
|
|
haloBlue, haloOrange, or a numerical color value. |
|
color |
Number |
Color for label text. |
|
disabledColor |
Number |
Color for label text when the component is disabled. |
|
embedFonts |
Boolean |
Set to true if the font specified in the fontFamily style is |
|
|
|
an embedded font, set to false otherwise. |
|
fontFamily |
String |
The name of the font to use for the label. |
|
fontSize |
Number |
The pixel size of the font to display for the label. |
|
fontStyle |
String |
The style of the label text. Possible values are normal and |
|
|
|
italic. |
|
fontWeight |
Number |
The weight of the label text. Possible values are bold and |
|
|
|
none. |
|
textDecoration |
Boolean |
Indicates whether the label text should be underlined. |
|
|
|
Possible values are underline and none. |
|
barColor |
Number |
The color of the progress bar. Has no effect with the default |
|
|
|
Halo theme. |
|
trackColor |
Number |
The color of the progress track. Has no effect with the |
|
|
|
default Halo theme. |
Strategies for Using Pre-Loaders
The structure of your main project determines in part how you implement a loader. Two approaches to consider are the monolithic movie approach and the split-up movie approach.
The Monolithic Movie Approach
If having a very responsive interface is important, or if you are just looking for a simple project structure and straightforward implementation, the monolithic movie approach is likely the one you will want to use. This approach suffers from a longer initial load time but benefits from quicker response once the movie has loaded. Many ways of implementing a pre-loader for a monolithic movie exist, only one of which we will talk about, which is the loader shim technique. This technique actually makes use of two movies. The first movie is the loader movie, sometimes referred to as a loader shim, which, because of its small size, loads to the user’s browser very quickly. Once loaded, the shim loads the primary .swf. This technique is very easy to implement. Just develop your project as you normally would, and then at the end create the loader shim and give it the path to your main movie.
217