ProblemYou want to load an external image into a movie while it plays. SolutionUse the new Loader class to load an image (.jpg, progressive .jpg, .png, or .gif) and display it on-screen. DiscussionRecipe 9.17 demonstrates how to embed external assets into a movie at compile time via the [Embed] metadata tag. To load external images or movies at runtime during the playback of a .swf, the Loader class needs to be used. The flash.display.Loader class is very similar to the flash.net.URLLoader class discussed in Recipe 19.3. One of the key differences is that Loader instances are able to load external images and movies and display them on-screen, whereas URLLoader instances are useful for transferring data. There are three fundamental steps for loading external content:
The load( ) method of the Loader class is responsible for downloading the image or .swf file. It takes a single URLRequest object as a parameter that specifies the URL of the asset to download and display. The following is a small example of using a Loader instance to download an image named image.jpg at runtime. The code in the LoaderExample constructor has been commented to coincide with the three basic loading steps previously outlined: package { import flash.display.*; import flash.net.URLRequest; public class LoaderExample extends Sprite { public function LoaderExample( ) { // 1. Create an instance of the Loader class var loader:Loader = new Loader( ); // 2. Add the Loader instance to the display list addChild( loader ); // 3. Call the load( ) method to pull in an external asset loader.load( new URLRequest( "image.jpg" ) ); } } } When running this code, the Flash Player looks for image.jpg in the same directory that the .swf movie is being served from because the URLRequest object uses a relative URL. Either a relative or absolute URL can be used to point to the location of the target to load, but the actual loading of the asset is governed by Flash Player's security sandbox, as discussed in Recipe 3.12. As soon as the asset has downloaded, it is automatically added as a child of the Loader instance. When loading external assets, it's possible that something could go wrong during the loading process. For instance, perhaps the URL is pointing to the incorrect location due to a spelling mistake, or there's a security sandbox violation that won't allow the asset to be loaded. Or, it's possible that the asset is large and is going to take a long time download. Rather than just having an empty screen while the asset downloads, you'd like to show a preloader to inform the user of the download progress. In these situations, you should add event listeners to the contentLoaderInfo property of the Loader instance to be able to respond to the different events as they occur. The contentLoaderInfo property is an instance of the flash.display.LoaderInfo class, designed to provide information about the target being loaded. The following is a list of useful events dispatched by instances of the LoaderInfo class and what those events mean:
The following example demonstrates listening for the various download progress related events when loading an image: package { import flash.display.*; import flash.text.*; import flash.net.URLRequest; import flash.events.*; public class LoaderExample extends Sprite { public function LoaderExample( ) { // Create the loader and add it to the display list var loader:Loader = new Loader( ); addChild( loader ); // Add the event handlers to check for progress loader.contentLoaderInfo.addEventListener( Event.OPEN, handleOpen ); loader.contentLoaderInfo.addEventListener( ProgressEvent.PROGRESS, handleProgress ); loader.contentLoaderInfo.addEventListener( Event.COMPLETE, handleComplete ); // Load in the external image loader.load( new URLRequest( "image.jpg" ) ); } private function handleOpen( event:Event ):void { trace( "open" ); } private function handleProgress( event:ProgressEvent ):void { var percent:Number = event.bytesLoaded / event.bytesTotal * 100; trace( "progress, percent = " + percent ); } private function handleComplete( event:Event ):void { trace( "complete" ); } } } When running the preceding code, you'll see the open message appear in the console window followed by one or more progress messages displaying the current percent loaded, followed by the complete message signaling that the download finished successfully. By placing code in the event handlers for these events, you can show the progress of a download as it's being loaded. For instance, the handleOpen( ) method would be in charge of creating the preloader and adding it to the display list. The handleProgress( ) method would update the percentage value of the preloader, such as setting the text of a TextField instance to the percent value. Finally, the handleComplete( ) method would perform "clean up" and remove the preloader, since the asset is fully downloaded. Focusing on those methods, the code might look something like this: private function handleOpen( event:Event ):void { // Create a simple text-based preloader and add it to the // display list _loaderStatus = new TextField( ); addChild( loaderStatus ); _loaderStatus.text = "Loading: 0%"; } private function handleProgress( event:ProgressEvent ):void { // Update the loading % to inform the user of progress var percent:Number = event.bytesLoaded / event.bytesTotal * 100; _loaderStatus.text = "Loading: " + percent + "%"; } private function handleComplete( event:Event ):void { // Clean up - preloader is no longer necessary removeChild( loaderStatus ); _loaderStatus = null; } The preceding code snippet assumes that there is a _loaderStatus variable as part of the class, with type TextField: private var _loaderStatus:TextField; Instead of messages appearing via the trace( ) statement as before, modifying the event handlers allows the loading information to be presented inside of the movie itself. This allows users to see the information directly and provides a better experience when loading large external assets. See AlsoRecipes 3.12, 6.7, 9.17, and 19.3 |