IN THIS CHAPTER
Loading SWFs and Images
Loading Data
Communicating with Loaded SWFs
Additional Online Resources
What’s Next?
You don’t always need to load external assets at runtime, but the ability to do so is extremely important. Loading assets on the fly reduces initial file size and, therefore, load times. It also increases the degree to which a Flash experience can change—not only through the all-important dynamic nature of runtime content updates, but also by streamlining the editing process. For example, you can alter external assets easier and faster than you can republish an FLA file every time an update occurs.
Augmenting prior discussions regarding sound, video, and plain text, this chapter will teach you how to load external SWFs and images. You’ll also take a peek at loading variables and binary data, and see how to increase your error checking efforts. Specifically, we’ll look at:
Loading SWFs and Images. Right out of the gate, it’s fairly easy to load SWFs and JPG, PNG, and GIF images. Third-party ActionScript libraries support loading even more asset types. We’ll look at simple syntax examples and then build a multipurpose class that can handle some error checking and reporting for you automatically.
Loading Data. Next we’ll discuss loading text, URL variables, and binary data. We discussed loading text from external sources in Chapter 10 but limited our coverage to loading HTML and CSS information. In this chapter, we’ll expand the scope of our discussion to loading URL-encoded variables and binary data. We’ll also write a multipurpose class you can use to load data. In Chapter 14 you’ll use that class to load XML.
Communicating with Loaded SWFs. After a SWF is loaded, the parent and child SWFs can communicate. We’ll discuss communication in both directions, and demonstrate a variety of tasks you may want to perform in the process.
Additional Online Resources. We’ll wrap up the chapter by referencing two additional loading-related topics discussed online. First we’ll describe problems caused by loading SWFs that use Text Layout Framework (TLF) assets (featured in Chapter 10). TLF assets use a custom preloader at runtime, which presents its own unique difficulties. We’ll point to two solutions, including Adobe’s new SafeLoader
class, designed to successfully load SWFs that use TLF. Finally, we’ll introduce a great new ActionScript 3.0 loading library called LoaderMax, created by GreenSock, the makers of TweenLite.
There are a few ways to load SWFs or images at runtime, but you’ll commonly use the Loader
class in one way or another. To simplify the process of loading these visual assets, the Loader
is also a display object. This makes it much easier to load and display visual assets because the Loader
itself can be added to the display list, rather than waiting for its content to finish loading. In addition, because it’s a display object, you can use a variety of properties and methods shared with other display objects, affecting position (x
, y
), transformation (alpha
, rotation
), event management (addEventListener()
) and more.
The following example is found in the load_swf.fla source file. Line 1 creates an instance of the Loader
class, line 2 loads a SWF using a URLRequest
instance, and line 3 adds the Loader
instance to the display list. Even if it takes some time for the remote SWF to load, the Loader
is already waiting, a little bit like a TV waiting for a program to begin.
1var
swfLoader:Loader
=new Loader
(); 2 swfLoader.load
(new URLRequest
("swfToLoad.swf"
)); 3addChild
(swfLoader);
One important difference between the Loader
class and other display object classes, such as MovieClip
, is that event listeners are usually attached to the contentLoaderInfo
property of the Loader
instance, rather than the instance itself. The property references an instance of the LoaderInfo
class, which traffics all information about the content of the Loader
.
For example, if you attached an event listener to the Loader
instance that listened for the COMPLETE
event, it would work without error, but would respond to the fact that the Loader
itself had loaded, not its content. As this is virtually instantaneous and doesn’t relate to the content you’re trying to load, it’s not very helpful. If you attached the same listener to the contentLoaderInfo
property of the Loader
instead, it would trigger its function when the content finished loading.
The following code, added to the prior example, stresses two concepts. First, it demonstrates attaching an event listener to the contentLoaderInfo
property, as discussed (lines 5 through 7), showing that the target of the listener is the LoaderInfo
instance described (line 10). Second, it shows that you can access the Loader
instance from the data sent with the event, as well as the content of the Loader
, as seen in lines 11 and 12, respectively. Note, too, that the example cleans up after itself by removing the COMPLETE
event listener in line 9, once the loading is finished.
4//use contentLoaderInfo for listeners
5 swfLoader.contentLoaderInfo.addEventListener
(Event.COMPLETE
, 6 onComplete, 7false
, 0,true
); 8function
onComplete(evt:Event
):void
{ 9 evt.target.removeEventListener
(Event.COMPLETE
, onComplete); 10trace
(evt.target
); 11trace
(evt.target.loader
); 12trace
(evt.target.loader.content
); 13 }
Waiting for the content of the Loader
to finish loading is important when you need to work with the content rather than just display it. For example, we discussed working with bitmaps in Chapter 9, both with and without adding them to the display list. For example, if you just want to load the bitmap data from the bitmap, you don’t need to add it to the display list. In this case, you can’t pull bitmap data from a Loader
instance and, even if you do want to add the Loader
content to the display list, you can’t add something that hasn’t yet loaded.
The following example, found in the load_jpg.fla source file, uses the same basic syntax as the previous example, but with two significant differences. First, it loads a JPG rather than a SWF. Second, it adds the JPG directly to the display list (line 9) instead of adding the Loader
instance. The result is a single child in the display list that is of type Bitmap
. As a demonstration of using Loader
properties, it also traces the bytesLoaded
and bytesTotal
of the loaded asset in lines 11 and 12. (After loading is complete, both numbers should be the same, no matter what the asset’s size.)
1var
jpgLoader:Loader
=new Loader
(); 2 jpgLoader.load
(new URLRequest
("imageToLoad.jpg"
)); 3 4 jpgLoader.contentLoaderInfo.addEventListener
(Event.COMPLETE
, 5 onComplete, 6false
, 0,true
); 7function
onComplete(evt:Event
):void
{ 8 evt.target.removeEventListener
(Event.COMPLETE
, onComplete); 9addChild
(evt.target.content
); 10 11trace
(evt.target.bytesLoaded
); 12trace
(evt.target.bytesTotal
); 13 }
The previous examples presented the simplest syntax for loading visual assets. Typical loading tasks are more involved, because they include additional features such as error checking and tracking loading progress.
Unfortunately, this can result in long scripts and become tedious quickly. So we’ll write a multipurpose class that will not only load SWF and image files, but will also report errors, monitor loading progress, and provide other diagnostic options, if you desire. The class will also mimic some of the features of the Loader
class, allowing you to use much of the same syntax you would use if writing the code from scratch each time using that class. This is helpful because one of the drawbacks of a do-it-all approach like this is less flexibility. If the new class resembles the existing Loader
class in useful ways, you can use the new class instead when you want a diagnostic environment rolled into a simple load, but revert to Loader
when you want more control.
You can even type the new class as Loader
when creating instances, so your code can be more flexible.
The class we want to write is called CustomLoader
and is in the in the loading directory of the learningactionscript3 package we’ve been developing throughout the book. We’ll be using this class with the load_swf_custom.fla and load_jpg_custom.fla source files, if you want to test it before proceeding.
Lines 1 through 9 declare the package and import all required classes. We’ll discuss classes from the flash.events
package that we haven’t mentioned before.
Line 11 declares the class and extends the Loader
class. This makes the accessible properties, methods, and events of the Loader
class available to our custom loader through inheritance. Lines 13 through 16 declare four private properties that will contain: a reference to the LoaderInfo
instance of the class inherited from Loader
(line 13), the path to the asset you want to load (line 14), a flag used to enable and disable trace statements (line 15), and a number between 0 and 1 representing the percentage of the asset’s bytes that have already been loaded (line 16).
See Chapter 6 for more information about inheritance.
1package
com.learningactionscript3.loading { 2 3import flash.display.Loader
; 4import flash.display.LoaderInfo
; 5import flash.events.Event
; 6import flash.events.HTTPStatusEvent
; 7import flash.events.IOErrorEvent
; 8import flash.events.ProgressEvent
; 9import flash.net.URLRequest
; 10 11public class
CustomLoaderextends Loader
{ 12 13private var
_ldrInfo:LoaderInfo
; 14private var
_path:String
; 15private var
_verbose:Boolean
=false
; 16private var
_loadedPercent:Number
= 0;
The constructor is pretty simple. It takes two arguments: the asset path and flag to show trace output, as mentioned previously, both with default values. Lines 20 and 21 populate class properties with data provided to the constructor during instantiation. Line 23 calls the addListeners()
method, which adds all the listeners used internally by the class (more on this in a moment).
The last lines of the constructor (25 through 31) load the requested asset if a path is passed into the constructor during instantiation. Providing a default value for path
, and checking path
before calling the load()
method, means that you can load assets in two ways. First, you can pass a simple string to the constructor during instantiation. In this case, path
will contain a String
, and load()
will be called in the constructor. Or, you can pass nothing to the class during instantiation (in which case path
will remain null, and load()
will not be called in the constructor) and use the load()
method from the class instance with a URLRequest
, just as you do with the Loader
class. We’ll demonstrate both techniques when we show usage examples.
Before we talk about the try..catch
block that surrounds the load()
method, note that no Loader
instance is created before loading. This is because the class you’re writing extends the Loader
class and, through inheritance, we can use its accessible methods, which include load()
. Therefore, the this
keyword is used instead, so the class loads the asset without having to create an additional Loader
.
A try..catch
block, discussed at the end of Chapter 2, allows you to try something but suppress a resulting error to prevent it from being seen by those viewing your SWF in the wild. You can use a try..catch
block in many ways. For example, you could try to load an asset from a remote server and, upon receiving an error, load a local version of the asset instead. More generically, you can use a try..catch
block when a runtime error is possible so the error doesn’t reach the user. It’s helpful to trace these errors and add descriptive messages, so it’s easier to track them down during development.
17//constructor
18public function
CustomLoader(path:String
=null
, 19 verbose:Boolean
=false
) { 20 _path = path; 21 _verbose = verbose; 22 23 addListeners(); 24 25if
(path !=null
) { 26try
{ 27this.load
(new URLRequest
(path)); 28 }catch
(err:Error
) { 29trace
("Cannot load"
, _path, err.message
); 30 } 31 } 32 }
The addListeners()
and removeListeners()
methods do nothing but add and remove listeners, respectively, but there are a few things worthy of note.
First, in line 35 the listeners are added to the contentLoaderInfo
property of the class (again, inherited from Loader
), as explained in the Loading SWFs section of this chapter.
Second, we’re adding several new events, including some that come from event classes we haven’t previously discussed. For completeness, let’s briefly go over when each event is dispatched.
Event.OPEN
: When the loading process is initiated. If this event is never received, you know loading never even started.
ProgressEvent.PROGRESS
: Each time data is received during the load. This allows you to update a loading progress bar.
HTTPStatusEvent.HTTP_STATUS
: When an HTTP request is made (such as fetching an asset from a server) and a status code is detected. For more information see http://en.wikipedia.org/wiki/List_of_HTTP_status_codes.
Event.INIT
: When enough of the loading process is complete to have access to the properties of the object. If, for example, you try to query the width of a loaded asset before this event is dispatched, it will likely be 0. After properties are accessible, the correct width will be available.
Event.COMPLETE
: When loading is finished. This occurs after Event.INIT
.
IOErrorEvent.IO_ERROR
: When an input/output error occurs. One example of such an error is when the asset can’t be found at the URL provided.
Event.UNLOAD
: When the asset is unloaded. This is usually the last event to be dispatched.
New to Flash Player version 10.1 is the uncaughtErrorEvents
property of the Loader
and LoaderInfo
classes. This allows you to trap any errors not caught by other means (such as a try..catch
block) in your code. For more information, see the “Trapping Uncaught Errors” post at the companion website, http://www.LearningActionScript3.com.
Lastly, notice that the removeListeners()
method is public. This allows you to remove all listeners from outside the class, when you’re through using the class instance you created. In some cases, you want to remove listeners right away, such as when you only need your listener once, as demonstrated in the examples earlier in this chapter. In other circumstances, you may want to use the same Loader
instance repeatedly to load asset after asset, in which case you want the listeners to remain active. The removeListeners()
method allows you to remove the listeners any time you like.
Another way to maintain your listeners is to add them before every load and remove them every time the load is complete. To keep your class as self-reliant as possible, you want to add the listeners when calling the load()
method. This requires that you override the load()
method, as discussed in the Polymorphism section of Chapter 6. The post, “Overriding the load() Method in Custom Loader Classes,” found at the companion website shows how this is done.
33//listeners
34private function
addListeners():void
{ 35 _ldrInfo =this.contentLoaderInfo
; 36 _ldrInfo.addEventListener
(Event.OPEN
, 37 onOpen,false
, 0,true
); 38 _ldrInfo.addEventListener
(ProgressEvent.PROGRESS
, 39 onProgress,false
, 0,true
); 40 _ldrInfo.addEventListener
(HTTPStatusEvent.HTTP_STATUS
, 41 onStatusEvent, 42false
, 0,true
); 43 _ldrInfo.addEventListener
(Event.INIT
, 44 onInit,false
, 0,true
); 45 _ldrInfo.addEventListener
(Event.COMPLETE
, 46 onComplete,false
, 0,true
); 47 _ldrInfo.addEventListener
(IOErrorEvent.IO_ERROR
, 48 onIOError,false
, 0,true
); 49 _ldrInfo.addEventListener
(Event.UNLOAD
, 50 onUnloadContent, 51false
, 0,true
); 52 } 53 54public function
removeListeners():void
{ 55 _ldrInfo.removeEventListener
(Event.OPEN
, onOpen); 56 _ldrInfo.removeEventListener
(ProgressEvent.PROGRESS
, 57 onProgress); 58 _ldrInfo.removeEventListener
(HTTPStatusEvent.HTTP_STATUS
, 59 onStatusEvent); 60 _ldrInfo.removeEventListener
(Event.INIT
, onInit); 61 _ldrInfo.removeEventListener
(Event.COMPLETE
, 62 onComplete); 63 _ldrInfo.removeEventListener
(IOErrorEvent.IO_ERROR
, 64 onIOError); 65 _ldrInfo.removeEventListener
(Event.UNLOAD
, 66 onUnloadContent); 67 }
The remainder of the class contains the listener methods, one getter, and one setter. The listener methods all trace specific feedback during the loading process, only if you pass true into the verbose flag during instantiation. Note, however, that the trace in the onIOError()
method is not wrapped in a conditional that uses the _verbose
Boolean. This is because we only want to turn on and off the logging feature, not any valid error reports. If the error were included in the list of items shown only when _verbose
is true, we would have to see all diagnostic text all the time just to see any input/output errors.
The onProgress()
method also calculates the percent that an asset has loaded. This way, if you want to create a progress bar, you can simply check the related property, percentLoaded
, via the getter at the end of the class, instead of calculating the value yourself. The onInit()
method also traces a few properties of the asset to help you in your loading diagnostics. The first is the asset’s URL (line 89) and, if the asset is a SWF, lines 93 through 96 trace the version of the Flash Player and ActionScript that the SWF was compiled for, and the SWF’s frame rate.
The percentLoaded
getter provides access to the _loadedPercent
property previously described, and the verbose
setter allows you to optionally turn on or off debugging through a property, rather than in the constructor.
In this class, enabling debugging through the constructor parameter or the verbose setter is entirely a matter of preference. The setter was provided to allow the instantiation of the class to more closely resemble the instantiation of the Loader
class.
68//listener methods, getter, and setter
69private function
onOpen(evt:Event
):void
{ 70if
(_verbose) {trace
("Loading begun:"
, _path); } 71 } 72 73private function
onProgress(evt:ProgressEvent
):void
{ 74 _loadedPercent = evt.bytesLoaded
/ evt.bytesTotal
; 75 76if
(_verbose) { 77trace
("Loading"
, _path, 78"-- progress (0-1):"
, _loadedPercent); 79 } 80 } 81 82private function
onStatusEvent(evt:HTTPStatusEvent
):void
{ 83if
(_verbose) {trace
("HTTP status:"
, evt.status
); } 84 } 85 86private function
onInit(evt:Event
):void
{ 87if
(_verbose) { 88trace
("Content initialized. Properties:"
); 89trace
("url:"
, evt.target
.url
); 90trace
("Same Domain:"
, evt.target
.sameDomain
); 91if
(evt.target
.contentType
== 92"application/x-shockwave-flash"
) { 93trace
("SWF Version:"
, evt.target
.swfVersion
); 94trace
("AS Version:"
, 95 evt.target
.actionScriptVersion
); 96trace
("Frame Rate:"
, evt.target
.frameRate
); 97 } 98 } 99 } 100 101private function
onComplete(evt:Event
):void
{ 102if
(_verbose) {trace
("Loading complete:"
, _path); } 103 } 104 105private function
onUnloadContent(evt:Event
):void
{ 106if
(_verbose) {trace
("Unloaded:"
, _path); } 107 } 108 109private function
onIOError(evt:IOErrorEvent
):void
{ 110trace
("CustomLoader loading error: "
, evt.text
); 111 } 112 113public function get
percentLoaded():Number
{ 114return
_loadedPercent; 115 } 116 117public function set
verbose(bool:Boolean
):void
{ 118 _verbose = bool; 119 } 120 } 121 }
Because we extended the Loader
class when writing CustomLoader
, both classes use similar syntax. The following examples replicate the previous examples closely to demonstrate this benefit of inheritance.
The first example, found in the load_swf_custom.fla, loads a SWF. After importing the class in line 1, line 3 passes the SWF’s path to the constructor during instantiation, and the class takes care of the URLRequest
and call to the load()
method. The only other difference between this script and the example shown in the Loading SWFs section is in line 11. Because the example makes no further use of the CustomLoader
class, all its listeners are removed.
1import
com.learningactionscript3.loading.CustomLoader; 2 3var
swfLoader:CustomLoader =new
CustomLoader("swfToLoad.swf"
,true
); 4addChild
(swfLoader); 5 6 swfLoader.contentLoaderInfo.addEventListener
(Event.COMPLETE
, 7 onComplete, 8false
, 0,true
); 9function
onComplete(evt:Event
):void
{ 10 evt.target.removeEventListener
(Event.COMPLETE
, onComplete); 11 evt.target
.loader
.removeListeners(); 12trace
(evt.target
); 13trace
(evt.target.content
); 14trace
(evt.target.loader
); 15 }
The event listeners in the example FLA files are not the same as the event listeners inside the class. All the internal listeners are at the class level, and are private so nothing outside the class is aware of their existence. The listeners in the example FLA files are applied to class instances.
The second example, found in the load_jpg_custom.fla, uses CustomLoader
much the same way Loader
is used. The instantiation process in line 3 passes no values to the constructor, the verbose flag is enabled in line 4, and loading is accomplished via the load()
method and a URLRequest
instance in line 5. Like the previous JPG loading example, this script also loads the JPG directly to the display list in the last instruction of the onComplete()
method.
This example also adds the use of the percentLoaded
getter to increase the horizontal scale of a progress bar. In line 7 the progress bar is created using the createProgressBar()
function found at the end of the script. The function creates a sprite, draws a green rectangle, and returns the sprite to the progressBar
variable. The sprite is then added to the display list in line 8.
Two listeners are then added to the contentLoaderInfo
property of the CustomLoader
instance, so the property is stored in a variable for efficiency. In addition to the COMPLETE
event listener found in the prior JPG loading example, a PROGRESS
event listener is added in lines 13 through 15. It calls the onProgress()
function in lines 17 through 19, which updates the scaleX
property of the progress bar sprite every time asset data is received during the loading process.
1import
com.learningactionscript3.loading.CustomLoader; 2 3var
jpgLoader:CustomLoader =new
CustomLoader(); 4 jpgLoader.verbose =true
; 5 jpgLoader.load
(new URLRequest
("imageToLoad.jpg"
)); 6 7var
progressBar:Sprite
= createProgressBar(); 8addChild
(progressBar); 9 10var
jpgLoaderInfo:LoaderInfo
= jpgLoader.contentLoaderInfo
; 11 jpgLoaderInfo.addEventListener
(Event.COMPLETE
, onComplete, 12false
, 0,true
); 13 jpgLoaderInfo.addEventListener
(ProgressEvent.PROGRESS
, 14 onProgress, 15false
, 0,true
); 16 17function
onProgress(evt:Event
):void
{ 18 progressBar.scaleX
= evt.target
.loader
.percentLoaded; 19 } 20 21function
onComplete(evt:Event
):void
{ 22 evt.target
.removeEventListener
(Event.COMPLETE
, onComplete); 23 evt.target
.loader
.removeListeners(); 24addChild
(evt.target.content
); 25 } 26 27function
createProgressBar():Sprite
{ 28var
sp:Sprite
=new Sprite
(); 29var
g:Graphics
= sp.graphics
; 30 g.beginFill
(0x00FF00); 31 g.drawRect
(0, 0, 100, 10); 32 g.endFill
(); 33 sp.x
= sp.y
= 10; 34return
sp; 35 }
If you want your usage of the Loader
and CustomLoader
classes to be as similar as possible, so you can switch between them with as few edits as possible, you can still enable verbose tracing without loading the asset immediately. You can set up your code like the custom JPG loading example, so the load()
method is used separately—just like using the Loader
class. However, when instantiating CustomLoader
(line 3 in the example), just pass in null and true as the parameter values:
new
CustomLoader(null
,true
);
This will enable verbose logging, but will not invoke the load()
method in the class constructor.
While the Loader
class will load visual assets, data such as text, URL variables, and even binary data, is loaded with the URLLoader
class. Using the URLLoader
class is similar in many ways to using the Loader
class. In fact, we’ll write a custom class for loading data that will closely resemble the programming design and syntax of the CustomLoader
class we wrote previously.
Just like the Loader
class can load more than one kind of object (SWF and image), URLLoader
can load three kinds of data, selected with the dataFormat
property of the URLLoader
instance. Plain text (such as text, HTML, CSS and so on) returns a string. URL-encoded variables (such as HTML form data and server responses) returns an instance of the URLVariables
class with a collection of variables and corresponding values. Binary data (such as image or sound data) returns a ByteArray
.
We introduced loading plain text in the Loading HTML and CSS section of Chapter 10, but we’ll cover it again here for completeness. We’ll also include examples of loading variables and binary data, including a beyond the basics look at how you can use binary data.
Loading XML is just like loading text. We’ll cover loading XML in detail in Chapter 14 and make use of the CustomURLLoader
class you’ll write in this chapter.
The default behavior of the URLLoader
class is to load text. The following example, found in the load_text.fla source file, is the simplest implementation of the URLLoader
class. All you need to do is instantiate the class (line 1), and load the text file using a URLRequest
instance. This example uses a COMPLETE
event listener to initialize a text field when the loading is finished (lines 4 through 15), populate the field with the text data sent with the event (line 13), and add the field to the display list (line 14).
1var
ldrText:URLLoader
=new URLLoader
(); 2 ldrText.load
(new URLRequest
("lorem.txt"
)); 3 4 ldrText.addEventListener
(Event.COMPLETE
, onComplete, 5false
, 0,true
); 6function
onComplete(evt:Event
):void
{ 7 evt.target
.removeEventListener
(Event.COMPLETE
, onComplete); 8var
txtFld:TextField
=new TextField
(); 9 txtFld.x
= txtFld.y
= 20; 10 txtFld.width
= 500; 11 txtFld.height
= 350; 12 txtFld.multiline
= txtFld.wordWrap
=true
; 13 txtFld.text
= evt.target
.data
; 14addChild
(txtFld); 15 }
One of the ways to send data between client and server is by using name-value pairs (also called attribute-value pairs). These are assembled in a URL like those sent from an HTML form or returned from some web applications like search tools. An example is firstname=Liz&lastname=Lemon.
If your project requires communication using URL variables, you must set the dataFormat
property of the URLLoader
class to URLLoaderDataFormat.VARIABLES
before loading. This automatically changes the data returned from the loading process to a URLVariables
object. Names and values are created in the object to match the names and values from the loading result. You can then access those properties to retrieve their values.
Web-based applications change frequently, so we’ve demonstrated this syntax using a local file written as URL variables. (Local URLs are no different to URLLoader
than remote server URLs.) The file vars.txt contains the following data:
name=Joe&age=25
This data will be loaded by the following example, found in load_vars.fla. The example assigns the dataFormat
property in line 2, and the property values are traced from the event target’s data property in lines 9 and 10.
1var
ldrVars:URLLoader
=new URLLoader
(); 2 ldrVars.dataFormat
=URLLoaderDataFormat.VARIABLES
; 3 ldrVars.load
(new URLRequest
("vars.txt"
)); 4 5 ldrVars.addEventListener
(Event.COMPLETE
, onComplete, 6false
, 0,true
); 7function
onComplete(evt:Event
):void
{ 8 evt.target
.removeEventListener
(Event.COMPLETE
, onComplete); 9trace
("name property:"
, evt.target.data
.name); 10trace
("age property:"
, evt.target.data
.age); 11 }
The following is the trace output:
//name property: Joe
//age property: 25
It’s also possible to load binary data from a URL, which is stored in a ByteArray
. In this book, we’ve already used the ByteArray
to load frequency spectrum data from sounds at runtime. ActionScript 3.0 has also been used to create FTP clients, VNC clients, and image loaders, just to name a few examples.
To send or load binary data with the URLLoader
class, you must set the dataFormat
property to URLLoaderDataFormat.BINARY
. The following example, found in the load_binary.fla source file, sets the property in line 2, loads an image in line 3, and, upon completing the load, creates a Loader
instance to read the bytes of data returned from the URLLoader
instance, and adds the instance to the display list (lines 9 through 11).
1var
imgLoader:URLLoader
=new URLLoader
(); 2 imgLoader.dataFormat
=URLLoaderDataFormat.BINARY
; 3 imgLoader.load
(new URLRequest
("imageToLoad.jpg"
)); 4 5 imgLoader.addEventListener
(Event.COMPLETE
, onComplete, 6false
, 0,true
); 7function
onComplete(evt:Event
):void
{ 8 evt.target
.removeEventListener
(Event.COMPLETE
, onComplete); 9var
ldr:Loader
=new Loader
(); 10 ldr.loadBytes
(evt.target
.data
); 11addChild
(ldr); 12 }
This example was designed to be simple to introduce the syntax for loading binary data. Later in the chapter, a beyond-the-basics example will use this technique to load a Pixel Bender filter to process an image.
Pixel Bender is an Adobe technology that lets you use a programming language based on C to write your own image filters.
Just as our CustomLoader
class extended the Loader
class, we want to extend the URLLoader
class and add similar automatic diagnostic features. We’ll call the new class CustomURLLoader
and, as before, we’ll design it to use familiar syntax so you can switch between URLLoader
and CustomURLLoader
relatively easily. This class is very similar to CustomLoader
in design and syntax, so our discussion will focus primarily on what makes it unique.
Lines 1 through 9 declare the package, and import all the required classes. The classes required are similar to those required by CustomLoader
, with the addition of the SecurityErrorEvent
class and the substitution of the URLLoader
class for Loader
. We’ll discuss the SecurityErrorEvent
class when we cover the listeners. Line 11 declares the class and extends URLLoader
. Again, this makes available the accessible properties and methods of the URLLoader
class. Lines 13 through 15 contain private properties also used in CustomLoader
to contain the asset path, the logging Boolean
, and a number that reports what percentage of the asset has loaded.
1package
com.learningactionscript3.loading { 2 3import flash.events.Event
; 4import flash.events.HTTPStatusEvent
; 5import flash.events.IOErrorEvent
; 6import flash.events.ProgressEvent
; 7import flash.events.SecurityErrorEvent
; 8import flash.net.URLLoader
; 9import flash.net.URLRequest
; 10 11public class
CustomURLLoaderextends URLLoader
{ 12 13private var
_path:String
; 14private var
_verbose:Boolean
; 15private var
_loadedPercent:Number
= 0;
The constructor is nearly identical to that of the CustomLoader
class. Starting with their similarities, this class accepts the asset path string and Boolean for verbose logging as arguments during instantiation (lines 17 and 18), populates the related properties (lines 20 and 21), adds the needed listeners (line 24), and tries to load the asset if a path was provided (lines 26 through 31). The big difference between the two classes is that this class also accepts the format
string argument, with a default value of “text” (line 19), and assigns that value to the dataFormat
property of the class, inherited from URLLoader
, (line 22).
16//constructor
17function
CustomURLLoader(path:String
=null
, 18 verbose:Boolean
=false
, 19 format:String
="text"
) { 20 _path = path; 21 _verbose = verbose; 22this.dataFormat
= format; 23 24 addListeners(); 25 26if
(path !=null
) { 27try
{ 28this.load
(new URLRequest
(path)); 29 }catch
(err:Error
) { 30trace
("URL load error:"
, err.message
); 31 } 32 } 33 }
The remainder of the class is also nearly identical to that of CustomLoader
. Starting with the event listeners, the addListeners()
and removeListeners()
methods also add and remove listeners, respectively (lines 35 through 63). The INIT
and UNLOAD
listeners are absent, as they do not apply to URLLoader
, and the SecurityErrorEvent.SECURITY_ERROR
has been added (lines 47 through 49, and 61 through 62). The latter is dispatched when you attempt to load data from a URL outside the security sandbox used by the SWF, and calls the method in lines 85 through 87.
Flash Player security is a big topic, which is discussed in greater detail on the companion website. Put simply, however, not every asset can be loaded without permission. Notably, a SWF can’t readily access the user’s local file system and remote URLs at the same time unless permission is granted, nor can you load content from different domains without permission—typically granted with a cross-domain policy file, which is an XML file on the remote server, listing any IP addresses that are allowed access. As your experience grows, and you start to work on projects where either of these needs arise, you’ll want to leave ample time to study security issues. See the post “Security Overview” on the companion website for more information.
When doing anything that might cause a possible security concern, including loading assets, test your work in a browser as often as is practical. Flash Professional is considered a trusted zone that is not susceptible to most Flash Player security issues. As a result you may think your file is working without security problems throughout development, only to find out at the last minute that restrictions do apply in the browser. The default settings of Flash Professional allow you to test in a browser easily using the Ctrl+F12 (Windows) or Cmd+F12 (Mac) keyboard shortcut.
Finally, the getter and setter (lines 93 through 99) are identical to those found in the CustomLoader
class, returning the percentage of bytes loaded, and enabling or disabling the verbose logging feature, respectively.
34//listeners
35private function
addListeners():void
{ 36this.addEventListener
(Event.OPEN
, 37 onOpen,false
, 0,true
); 38this.addEventListener
(ProgressEvent.PROGRESS
, 39 onProgress,false
, 0,true
); 40this.addEventListener
(HTTPStatusEvent.HTTP_STATUS
, 41 onStatusEvent, 42false
, 0,true
); 43this.addEventListener
(Event.COMPLETE
, 44 onComplete,false
, 0,true
); 45this.addEventListener
(IOErrorEvent.IO_ERROR
, 46 onIOError,false
, 0,true
); 47this.addEventListener
(SecurityErrorEvent.SECURITY_ERROR
, 48 onSecError, 49false
, 0,true
); 50 } 51 52public function
removeListeners():void
{ 53this.removeEventListener
(Event.OPEN
, onOpen); 54this.removeEventListener
(ProgressEvent.PROGRESS
, 55 onProgress); 56this.removeEventListener
(HTTPStatusEvent.HTTP_STATUS
, 57 onStatusEvent); 58this.removeEventListener
(Event.COMPLETE
, onComplete); 59this.removeEventListener
(IOErrorEvent.IO_ERROR
, 60 onIOError); 61this.removeEventListener
(SecurityErrorEvent.SECURITY_ERROR
, 62 onSecError); 63 } 64 65private function
onOpen(evt:Event
):void
{ 66if
(_verbose) {trace
("Loading begun:"
, _path); } 67 } 68 69private function
onProgress(evt:ProgressEvent
):void
{ 70 _loadedPercent = evt.bytesLoaded
/ evt.bytesTotal
; 71if
(_verbose) { 72trace
("Loading"
, _path, 73"-- progress (0-1):"
, _loadedPercent); 74 } 75 } 76 77private function
onStatusEvent(evt:HTTPStatusEvent
):void
{ 78if
(_verbose) {trace
("HTTP status:"
, evt.status
); } 79 } 80 81private function
onComplete(evt:Event
):void
{ 82if
(_verbose) {trace
("Loading complete:"
, _path); } 83 } 84 85private function
onSecError(evt:SecurityErrorEvent
):void
{ 86trace
("Security error:"
, evt.text
); 87 } 88 89private function
onIOError(evt:IOErrorEvent
):void
{ 90trace
("Loading error:"
, evt.text
); 91 } 92 93public function get
percentLoaded():Number
{ 94return
_loadedPercent 95 } 96 97public function set
verbose(bool:Boolean
):void
{ 98 _verbose = bool; 99 } 100 } 101 }
As with the CustomLoader
class, the companion website includes an alternate version of CustomURLLoader
that overrides the load()
method. This simplifies the use of both classes because their internal listeners—those responsible for the verbose logging—are added and removed automatically. See the post, “Overriding the load() Method in Custom Loader Classes,” at the companion website, http://www.LearningActionScript3.com.
As you might imagine from their complementary design, using the CustomURLLoader
class is very similar to using the CustomLoader
class. We’ll show examples for loading text, variables, and binary data.
The following example, found in the load_text_custom.fla source file, is a simple use of the class. It passes the path of the text file into the class constructor to let the class handle the loading (lines 3 and 4), and it uses verbose logging so you can see what’s going on. Other than using our custom class and removing its internal listeners (line 10), it’s the same in every other respect as the basic text-loading example explained earlier in the chapter.
1import
com.learningactionscript3.loading.CustomURLLoader; 2 3var
ldrText:CustomURLLoader =new
CustomURLLoader("lorem.txt"
, 4true
); 5 6 ldrText.addEventListener
(Event.COMPLETE
, onComplete, 7false
, 0,true
); 8function
onComplete(evt:Event
):void
{ 9 evt.target
.removeEventListener
(Event.COMPLETE
, onComplete); 10 evt.target
.removeListeners(); 11var
txtFld:TextField
=new TextField
(); 12 txtFld.x
= txtFld.y
= 20; 13 txtFld.width
= 500; 14 txtFld.height
= 350; 15 txtFld.multiline
= txtFld.wordWrap
=true
; 16 txtFld.text
= evt.target
.data
; 17addChild
(txtFld); 18 }
The next example, found in the load_vars_custom.fla source file, employs syntax similar to what you used with the URLLoader
class. The class is instantiated with no arguments (line 3), the dataFormat
property is set separately (line 4), and the load()
method is called using a URLRequest
instance (line 5).
Two things that are different than the previous variable loading example are the removal of the self-contained class listeners (line 11) and the fact that the event listener method demonstrates using a for..in
loop (lines 12 through 14) to iterate through all variables, rather than retrieving their values by name.
1import
com.learningactionscript3.loading.CustomURLLoader; 2 3var
ldrVars:CustomURLLoader=new
CustomURLLoader(); 4 ldrVars.dataFormat
=URLLoaderDataFormat.VARIABLES
; 5 ldrVars.load
(new URLRequest
("vars.txt"
)); 6 7 ldrVars.addEventListener
(Event.COMPLETE
, onComplete, 8false
, 0,true
); 9function
onComplete(evt:Event
):void
{ 10 evt.target
.removeEventListener
(Event.COMPLETE
, onComplete); 11 evt.target
.removeListeners(); 12for
(var
propin
evt.target.data
) { 13trace
(prop +": "
+ evt.target.data
[prop]); 14 } 15 }
The final use of our CustomURLLoader
class will again demonstrate loading binary data. This time, however, we’ll load a Pixel Bender filter. Adobe developed Pixel Bender to allow users to program image processing filters using a C-based language. Filters are typically written using the Pixel Bender Toolkit (an integrated development environment created expressly for this purpose) and then used by other Adobe applications like Photoshop, AfterEffects, and Flash Player.
You don’t have to be able to write the filters to use them, however. Many filters exist under a variety of licenses, including open source, freeware, shareware, and commercial. One place to find Pixel Bender filters is the Adobe Pixel Bender Exchange. Visit http://www.adobe.com/cfusion/exchange/, select the Pixel Bender exchange, and then browse or search for filters that can be used with Flash.
You can learn more about Pixel Bender from the Pixel Bender Developer Center: http://www.adobe.com/devnet/pixelbender/.
In this example, we’ll use the SquarePattern filter created by the talented Flash Platform evangelist, teacher, and developer Lee Brimelow. You can read about it at Lee’s blog, The Flash Blog, at http://blog.theflashblog.com/?p=432.
Lee Brimelow also created the Pixel Bender Viewer, a tool that allows you to load Pixel Bender filters, experiment with their settings, and export them in a format compatible with Flash Player. For more information, see http://blog.theflashblog.com/?p=385.
In ActionScript, this process begins by creating a shader using the Shader
class. A shader defines a function that executes on all the pixels of an image, one pixel at a time. Shaders can be used for filters, fills, blend modes, and even numeric calculations. The benefit of these efforts is that Pixel Bender shaders can improve performance of these processor-intensive tasks. In this example, we’ll create a filter using the ShaderFilter
class.
The following class, CustomLoadBinaryExample.as, is a document class used by the accompanying CustomLoadBinaryExample.fla source file. It will use the CustomLoader
class to import an image and add it to the display list, then load the SquarePattern
filter using the CustomURLLoader
class, and finally animate the filter using an enter frame event listener.
Lines 1 through 11 declare the package and import all the required classes. Line 13 declares the class, which extends MovieClip
so it can be used as a document class, if desired. Lines 15 through 20 declare a set of private properties that will hold the CustomLoader
’s LoaderInfo
instance (line 15), the loaded image (line 16), a CustomURLLoader
instance (line 17), the Pixel Bender Shader
and ShaderFilter
(lines 18 and 19), and a property to hold the changing filter values during animation (line 20).
The constructor (lines 22 through 29) then uses the CustomLoader
class to load an image (lines 23 and 24) and create an event listener to respond to the COMPLETE
event (lines 25 through 28).
1package
{ 2 3import flash.display.Bitmap
; 4import flash.display.LoaderInfo
; 5import flash.display.MovieClip
; 6import flash.display.Shader
; 7import flash.filters.ShaderFilter
; 8import flash.events.Event
; 9import flash.net.URLLoaderDataFormat
; 10import
com.learningactionscript3.loading.CustomLoader; 11import
com.learningactionscript3.loading.CustomURLLoader; 12 13public class
CustomLoadBinaryExampleextends MovieClip
{ 14 15private var
_ldrInfo:LoaderInfo
; 16private var
_penguins:Bitmap
; 17private var
_ldrBinary:CustomURLLoader; 18private var
_shader:Shader
; 19private var
_shaderFilter:ShaderFilter
; 20private var
_val:Number
= 0; 21 22public function
CustomLoadBinaryExample() { 23var
jpgLoader:CustomLoader = 24new
CustomLoader("penguins.jpg"
); 25 _ldrInfo = jpgLoader.contentLoaderInfo
; 26 _ldrInfo.addEventListener
(Event.COMPLETE
, 27 onImgLoaded, 28false
, 0,true
); 29 }
Once the image has loaded, the onImgLoaded()
method (lines 31 through 44) is called. The COMPLETE
event listener is removed from the CustomLoader
’s LoaderInfo
instance (lines 32 and 33), the class’s internal listeners are removed (line 34), and the loaded bitmap is then added to the display list (lines 35 and 36). Next, the CustomURLLoader
class is used to load the Pixel Bender filter file as binary data (lines 38 through 40), and another COMPLETE
listener is created (lines 41 through 43)—this time calling its method when the filter is completely loaded.
30//load filter
31private function
onImgLoaded(evt:Event
):void
{ 32 evt.target
.removeEventListener
(Event.COMPLETE
, 33 onImgLoaded); 34 evt.target.loader
.removeListeners(); 35 _penguins =Bitmap
(evt.target.content
); 36addChild
(penguins); 37 38 _ldrBinary = 39new
CustomURLLoader("squarepattern.pbj"
,true
, 40URLLoaderDataFormat.BINARY
); 41 _ldrBinary.addEventListener
(Event.COMPLETE
, 42 onFilterLoaded, 43false
, 0,true
); 44 }
When the filter file is loaded, the onFilterLoaded()
method (lines 46 through 55) is called. The COMPLETE
event listener is removed from the CustomURLLoader
(lines 47 and 48), and the class’s internal listeners are removed on line 49. Next a Shader
instance is created from the loaded Pixel Bender data, and a ShaderFilter
instance is derived from the Shader
instance. The last task of the method sets up the filter animation by creating an enter frame event listener (lines 53 through 54).
45//create Shader and ShaderFilter
46private function
onFilterLoaded(evt:Event
):void
{ 47 _ldrBinary.removeEventListener
(Event.COMPLETE
, 48 onFilterLoaded); 49 evt.target
.removeListeners(); 50 _shader =new Shader
(evt.target.data
); 51 _shaderFilter =new ShaderFilter
(shader); 52 53this.addEventListener
(Event.ENTER_FRAME
, onEnter, 54false
, 0,true
); 55 }
Finally, the enter frame event listener method onEnter()
(lines 57 through 66) animates the filter. First, the filter is assigned to the Bitmap
instance’s filters
property, as discussed in Chapter 9. Next the _val
property is incremented (line 60). Then the _val
property is used to update the SquarePattern’s amount
property value. The property takes an array of three numbers: minimum, maximum, and default. We’ve set the maximum to 50, and the default to 0, and we’re incrementing the minimum by 1 every enter frame. When the value reaches 50, the event listener is removed, halting the animation (lines 62 through 65).
56//adjust filter values
57private function
onEnter(evt:Event
):void
{ 58 _penguins.filters
= [_shaderFilter]; 59 60 _val++; 61 _shader.data
.amount.value
= [_val, 50, 0]; 62if
(_val >= 50) { 63this.removeEventListener
(Event.ENTER_FRAME
, 64 onEnter); 65 } 66 } 67 } 68 }
Now that you know how to load SWFs, let’s talk about communicating between them. For this discussion, we’ll reference the Loader
class, but the ideas in this section apply equally to the CustomLoader
class.
To see the CustomLoader
class used in this context, consult the nearly identical source files, communication_child_custom.fla and communication_parent_custom.fla. For these examples to work, the child SWF must exist before testing the parent SWF.
The key to communicating between a parent SWF created with ActionScript 3.0 and a loaded SWF created with ActionScript 3.0 is understanding the position of the Loader
instance between the two SWFs. Within the parent, accessing the child SWF is straightforward because you need only do so through the Loader
instance. The same is true in the other direction, from child to parent, but is less obvious to some. Just like when traversing the display list, you can use this.parent
within a loaded child SWF to talk to its parent. However, this will refer to the Loader
instance, not the SWF’s main timeline (or document class) scope.
SWFs created with ActionScript 3.0 cannot talk directly to SWFs created with ActionScript 2.0 or ActionScript 1.0. If you must do this, such as when showcasing legacy projects in a new portfolio site, you can do so with a workaround that establishes a LocalConnection
channel between the SWFs. For more information, see the “Sending Data from AVM2 to AVM1” post on the companion website.
The following examples, found in the communication_parent.fla and communication_child.fla source files, demonstrate several tasks you may need to perform when communicating between parent and child SWFs, including getting or setting properties, calling methods, and calling functions. This exercise shows communication in both directions. Both SWFs contain a simple movie clip animation, a function, and a variable. They both trace information to help you understand what’s happening when the parent SWF loads the child SWF into a Loader
instance.
Lines 1 through 7 provide the code that is self-contained within the child SWF, which the parent will manipulate. Line 1 initially stops the animation so we can demonstrate the parent calling the MovieClip play()
method. We’ll show you when this occurs in the parent script, but after loading, the animation should play. Line 3 creates and populates a string variable, the content of which states that it exists inside the child SWF. Lines 5 through 7 define a function that traces a string passed to it as an argument. This string will originate in the parent SWF to demonstrate calling a function in the child SWF.
Lines 9 through 25 contain the inter-SWF communication, but the conditional beginning in line 9 is necessary to prevent errors when testing the SWF prior to loading. The conditional simply checks to see if the parent of the SWF’s main timeline is the stage. As we discussed in Chapter 4 when covering the display list, there is only one stage and, when a SWF is on its own, its parent is the stage. If this is true, the child will trace [object Stage] in line 11, and show that the stage has no other parent by tracing null in line 12. We’ll discuss what happens when the SWF’s parent is not the stage after the code.
1 childAnimation.stop
(); 2 3var
stringMsg:String
="STRING INSIDE CHILD"
; 4 5function
childFunction(msg:String
):void
{ 6trace
("traced from function within child:"
, msg); 7 } 8 9if
(this.parent
==this.stage
) { 10trace
("child without being loaded:"
); 11trace
(" my parent:"
,this.parent
); 12trace
(" my parent's parent:"
,this.parent.parent
); 13 }else
{ 14trace
("child communicating with parent:"
); 15var
parentLoader:Loader
=Loader
(this.parent
); 16var
parentApp:MovieClip
=MovieClip
(this.parent.parent
); 17trace
(" my parent:"
, parentLoader); 18trace
(" getting my parent's property:"
, parentLoader.x
); 19trace
(" my parent's parent:"
, parentApp); 20 parentApp.stringMsg ="NEW STRING INSIDE PARENT"
; 21trace
(" my parent's parent's redefined variable:"
, 22 parentApp.stringMsg); 23 parentApp.parentFunction("message from child"
); 24 parentApp.parentAnimation.play
(); 25 }
If the child SWF’s parent is not the stage, lines 15 and 16 cast the parent to a Loader
instance and the parent’s parent (which is the main timeline of the SWF doing the loading) to a MovieClip
instance. Line 17 then traces the Loader
instance, and line 18 traces a property of that Loader
. Line 20 demonstrates setting a variable in another SWF by changing the string variable in the parent. (We’ll see that variable in a moment, but it’s equivalent to line 3 in the child). Lines 21 and 22 then get and trace that variable. Finally, line 23 calls a function in the parent (passing a string argument in the process), and line 24 plays the movie clip in the parent.
The parent SWF requires no conditional, but is responsible for loading the child SWF. Lines 1 through 7 perform similar roles to the corresponding lines in the child SWF—initially stopping a movie clip animation, declaring and populating a string variable, and defining a function that accepts a string as an argument. The variable in line 3 is the same one redefined by the child SWF in its line 20, and the function in line 5 is the same one called by the child SWF in its lines 21 and 22.
Lines 9 through 15 should be familiar territory by now. They create a Loader
instance, add it to the display list, load the child SWF, and create a COMPLETE
event listener that calls the function in line 16 when the event is heard. Line 17 casts the content of the Loader
(the child SWF) as a MovieClip
, line 19 traces the child SWF’s variable, line 21 calls the child SWF’s function, and line 22 plays the child SWF’s movie clip.
1 parentAnimation.stop
(); 2 3var
stringMsg:String
="STRING INSIDE PARENT"
; 4 5function
parentFunction(msg:String
):void
{ 6trace
("traced from within parent:"
, msg); 7 } 8 9var
ldr:Loader
=new Loader
(); 10addChild
(ldr); 11 ldr.load
(new URLRequest
("communication_child.swf"
)); 12 13 ldr.contentLoaderInfo.addEventListener
(Event.COMPLETE
, 14 onComplete, 15false
, 0,true
); 16function
onComplete(evt:Event
):void
{ 17var
childSWF:MovieClip
=MovieClip
(ldr.content
); 18trace
(" parent communicating with child:"
); 19trace
(" getting my child's variable:"
, 20 childSWF.stringMsg); 21 childSWF.childFunction("message from parent"
); 22 childSWF.childAnimation.play
(); 23 }
The source files communication_parent_custom.fla and communication_child_custom.fla replicate the scripts in this section but use the CustomLoader
class for all loading.
The companion website also contains an example of communication between parent and child SWF without using a Loader
instance. See the post “SWF Communication without Going Through Loader.”
We want to wrap up by drawing attention to two important loading-related issues that we’ve documented in detail online. The first is a workaround for a problem that occurs when loading SWFs that contain Text Layout Framework (TLF) assets (discussed in Chapter 10). The second is a third-party ActionScript package called LoaderMax that brings a lot of power and convenience to the loading process.
TLF uses a Runtime Shared Library (RSL)—an external library of code with an .swz extension that’s loaded at runtime. If a user doesn’t already have the correct version of the RSL on his or her computer, the TLF asset will try to download it from the Adobe website. Failing that, a version of the RSL from the same directory as the SWF will be loaded.
Runtime shared libraries can have a .swz extension if compressed, and a .swc extension if not compressed.
Because RSLs are external, it’s possible to experience a short delay when viewing TLF assets. (Ideally this occurs only the first time, as RSLs should be cached on your computer thereafter.) To compensate for this possible delay, Adobe included a preloader that’s automatically added to any SWF that uses TLF.
If you ever see an animated line of five dots before a TLF asset displays, that’s its preloader at work.
Unfortunately, this setup causes problems after loading SWFs with TLF assets. The most common problem is that you can’t communicate between parent and child, as described in the Communicating with Loaded SWFs section of this chapter, because of the extra layers of loaders that are inserted into the display list by the TLF asset.
There are essentially two solutions to this problem, both of which are discussed on the companion website in the “Loading SWFs that Use TLF” post. The first is to compile the TLF Runtime Shared Library code into your SWF. This makes the entire setup internal, but also increases your SWF’s file size by about 120k. The second solution is to use Adobe’s new SafeLoader
class.
The SafeLoader
class is a replacement for the Loader
class (it doesn’t extend Loader) and is available for download from the following Adobe Technote: http://kb2.adobe.com/cps/838/cpsid_83812.html. Its use is nearly identical to the Loader
class, and you only really need to use it when you know you’re loading TLF assets. Sample code is provided with the class in the cited download. We’ll also use it in the XML navigation bar in Chapter 14.
The SafeLoader
class was released soon after Flash Professional CS5 was released and may still have some issues to grapple with. We discuss such issues in the aforementioned companion website post, so be sure to review it before using the class.
TLF assets also affect preloading code designed to preload the SWF in which the code resides. That is, instead of loading an external asset, this kind of preloading code sits in frame 1 of the SWF and loops back to frame 1 until the SWF is fully loaded. Once the SWF is loaded, the code then moves the playhead on to the next frame.
Flash Professional CS5 users can see an example of a self-preloader in the templates that ship with the application. Select the File✓New menu option, and then select the Templates tab in the dialog box that appears. Choose the Sample Files category and select the Preloader for SWF template. You can then see the preloading code in frame 1.
If you are not using Flash Professional CS5, you can search the web using the phrase “AS3 preloader internal” for many examples to find one that suits your coding style. Because links change often, the companion website will provide a link to both a class-based and timeline-based example in the cited post.
A fitting end to this chapter is a quick blurb about LoaderMax. Brought to you by GreenSock, the makers of TweenLite, LoaderMax is the crème de la crème of ActionScript 3.0 loading libraries. Adding as little as 7k to your SWF (depending on which classes you need to use), LoaderMax loads SWFs, images, XML, videos, MP3s, CSS, data, and more. LoaderMax simplifies and enhances loading the way TweenLite simplifies and enhances tweening. For example, here are some of the things LoaderMax can do:
Build loaders in a variety of ways, including single-item loaders from nothing more than a String
path (LoaderMax can automatically determine which type of loader to use based on the file extension) and loader queues automatically assembled from XML documents
Build a queue that intelligently loads assets in the order specified but that can easily reprioritize the queued assets on the fly
Show progress of individual loaders or all loaders as a group
Easily add robust event listeners, including multiple events in a single line of code
Integrate subloaders (LoaderMax instances that exist inside an asset being loaded) with the overall progress and event model of the main loader
Provide an alternate URL that will automatically be used in the event the first URL fails
Pause and resume loads in progress
Circumvent existing ActionScript loading and unloading issues with improved garbage collection, including properly loading SWFs with TLF assets
Optionally manipulate many display characteristics include automatic scaling, image smoothing, centering registration points, and more
Operationally control video and MP3 assets, including methods that play, pause, and go to specific time; properties that get or set volume, time, and duration; and events that monitor playback progress and more
Provide a substantial number of shared properties, methods, and events to all loader types improving consistency and saving lots of manual labor.
LoaderMax is easy to learn and use, particularly after you’re familiar with the ActionScript 3.0 loading process. Ideally, this chapter has provided you with the groundwork to get you started, and you can consider using LoaderMax for your next project. For more information, visit http://www.LoaderMax.com.
Throughout this book, we’ve demonstrated a few examples of loading external assets. Previously, we discussed loading HTML and CSS (Chapter 10), sound (Chapter 11), and video (Chapter 12). In this chapter, we focused on loading SWF and image assets, as well as text, URL variables, and binary data. We also extended the Loader
and URLLoader
classes to add some basic diagnostic features to make it easier to check on your loading efforts. Finally, we discussed communication with loaded SWFs and provided a few online resources that touch on additional loading-related topics. With this information as a head start, you should be able to begin working with just about any basic external asset, and begin explorations into intermediate and advanced loading issues.
Next we’re going to cover XML, which is among the most important standard formats used for data exchange, and E4X, the dramatically simplified approach to working with XML in ActionScript. XML is very widely used and enables a significant leg up over name-value pairs when it comes to structured data and large data sizes.
In the next chapter, we’ll cover:
The basics of the XML format
Reading, writing, and editing XML data
Loading XML assets using the CustomURLLoader
class from this chapter
XML communication with servers and other peers
3.144.8.90