Friday, 17 June 2011

Simple preloader for the Loader Class

I use the Loader class mainly to... well, load an image. It's also used to load external SWF, but at this time, I didn't had the need to use it like that.

My main job, at this point, as an AS3 developer is to produce infographies for a news agency. Some processes ahve change in the way I must now deliver the work, and one big change is that all the assets like images, videos, sounds and xml files, must be in a remote server.

This carries a problem which is a possible lag in time while the SWF tries and loads the assets remotely. You have to take care of this, because the web readers of these infos must have some sort of feedback, or else, nothing happens, and they may think something is broken.

So this time I'll tell you a simple way of making a preloader bar for the Loader class.

Make a simple class to load the image:

package{
     import flash.display.MovieClip;
     import flash.display.Loader;
     import flash.display.URLRequest;


     public class LoadPhoto extends MovieClip{
          private var photoURL:URLRequest;
          private var photoLoader:Loader;


          public function LoadPhoto(url:String){
              photoURL=new URLRequest(url);
              photoLoader=new Loader();
              photoLoader.load(photoURL);
              addChild(photoLoader);
         }
     }
}

This is the minimum to load an image or SWF with the Loader.

If you want to show a progress bar while the data is accessed, you have to draw it. You can add a text field to show the percentage value, but that it's a natural evolution from this progress bar.

Inside the the LoadPhoto function add the necessary code to make a simple line using a Sprite:

progressBar=new Sprite();
progressBar.graphics.lineStyle(3, 0x0000CC); //define thickness and color
progressBar.graphics.moveTo(0,0); //initial point of the line
progressBar.graphics.lineTo(imageWidth, 0); //the line will be on top
progressBar.scaleX=0; //in the beggining the progressBar will be a dot
addChild(progressBar);

Then we have to catch the size of the data that is been received, and of course it's total amount. We have to associate an event to the Loader to catch these values. For that we have to use the ProgressEvent class. So First of all add to the imports block import.events.ProgressEvent.
Then add this line after the end of the LoadPhoto function:

photoLoader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, progressHandler);

Then define a new function that handles this event:

private function progressHandler(evt:ProgressEvent):void{
     progressBar.scaleX=(evt.bytesLoaded/evt.bytesTotal);
}

This last function will receive the loaded bytes and the total byte size, and turn them into a value between 0 and 1, which is what we need to define the scaleX of the Bar. You can later add an event listener to remove the progressBar and show the asset.

In the end the Class with the Loader and a progress bar, will be something like this:


package{
     import flash.display.MovieClip;
     import flash.display.Sprite;
     import flash.display.Loader;
     import flash.display.URLRequest;
     import flash.events.ProgressEvent;

     public class LoadPhoto extends MovieClip{
          private var photoURL:URLRequest;
          private var photoLoader:Loader;
          private var progressBar:Sprite;

          public function LoadPhoto(url:String){
              progressBar=new Sprite();
              progressBar.graphics.lineStyle(3, 0x0000CC); //define thickness and color
              progressBar.graphics.moveTo(0,0); //initial point of the line
              progressBar.graphics.lineTo(imageWidth, 0); //the line will be on top
              progressBar.scaleX=0; //in the beggining the progressBar will be a dot
              addChild(progressBar);

              photoURL=new URLRequest(url);
              photoLoader=new Loader();
              photoLoader.load(photoURL);
              addChild(photoLoader);
 photoLoader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, progressHandler);
         }
         
         private function progressHandler(evt:ProgressEvent):void{
              progressBar.scaleX=(evt.bytesLoaded/evt.bytesTotal);
         }
     }
}