Creating an XML Slideshow in Flash Using AS3
By Riyadh Al Balushi | Flash CS4 | ActionScript 3.0| Intermediate | Page 1, 2, 3, 4, 5, 6In the final section of the tutorial we are going to add a hidePrev() function to remove the previous image and its label so that they do not build up behind existing images. We will also optimize the code to avoid any bugs during playback and finally add a simple message while the images are loading.
Here is the basic outline of this section:
- Create a hidePrev() function.
- Optimize the code.
- Create a simple preloading message.
Creating the hidePrev() function
The problem of our multiplying text labels and images can be cured by creating a function to hide the existing image and label from the screen before showing the next one. We will invoke this function before we update the my_current_playback counter or even call the nextImage() function. We want to remove the first image and label displayed on the screen, so we can refer to them using their position on their perspective display lists. We can then simply use the Tween Class to fade them out. You can type the following code at the bottom of your existing work to do this:
var my_image:Loader=Loader(my_image_slides.getChildAt(0));
new Tween(my_image,"alpha",Strong.easeOut,1,0,1,true);
var my_label:TextField=TextField(my_label_slides.getChildAt(0));
new Tween(my_label,"alpha",Strong.easeOut,1,0,1,true);
}
You can now call this function from within your Timer event listener function:
hidePrev();
my_playback_counter++;
if (my_playback_counter == my_total){
my_playback_counter =0;
}
nextImage();
}
Testing this code will only fade out the first slide but nothing else, this happens because all other images and labels are positioned beyond index 0 in their respective display lists as long as the first one remains there. We need to remove the image and label from the display list after they are faded out. To do this we need to register one of our Tweens with an event listener. In order to do this we need to create a permanent variable for our tween at the beginning of our code:
var my_total:Number;
var my_images:XMLList;
var my_loaders_array:Array = [];
var my_labels_array:Array = [];
var my_success_counter:Number = 0;
var my_playback_counter:Number = 0;
var my_slideshow:Sprite = new Sprite();
var my_image_slides:Sprite = new Sprite();
var my_label_slides:Sprite = new Sprite();
var my_timer:Timer;
var my_prev_tween:Tween;
var my_xml_loader:URLLoader = new URLLoader();
my_xml_loader.load(new URLRequest("slideshow.xml"));
my_xml_loader.addEventListener(Event.COMPLETE, processXML);
Now you can update your hidePrev() function and then add an event listener. Both the image and label tweens take the same amount of time to be completed, for this reason we can remove them using the same event listener instead of using a separate one for each one.
var my_image:Loader=Loader(my_image_slides.getChildAt(0));
my_prev_tween = new Tween(my_image,"alpha",Strong.easeOut,1,0,1,true);
my_prev_tween.addEventListener(TweenEvent.MOTION_FINISH, onFadeOut)
var my_label:TextField=TextField(my_label_slides.getChildAt(0));
new Tween(my_label,"alpha",Strong.easeOut,1,0,1,true);
}
We can now create the onFadeOut() event listener function to remove the child at position 0 for each of the display containers:
my_image_slides.removeChildAt(0);
my_label_slides.removeChildAt(0);
}
That should do it! You can now test your slideshow to see that it works like a charm!
Adding a Simple Preloader Text
Depending on the number of images you have on your slidehsow, downloading these might take a long while to complete. To inform that user that the movie is not stuck and that loading is in progress, we can add such simple text to do this. We are going to add this text right after we load all the images using the loop and hide it when the show starts.
The first step in creating this preloader is creating the variable that will host the textfield. Create this at the top of your code as we need this to be a permenant reference:
var my_total:Number;
var my_images:XMLList;
var my_loaders_array:Array = [];
var my_labels_array:Array = [];
var my_success_counter:Number = 0;
var my_playback_counter:Number = 0;
var my_slideshow:Sprite = new Sprite();
var my_image_slides:Sprite = new Sprite();
var my_label_slides:Sprite = new Sprite();
var my_preloader:TextField;
var my_timer:Timer;
var my_prev_tween:Tween;
var my_xml_loader:URLLoader = new URLLoader();
my_xml_loader.load(new URLRequest("slideshow.xml"));
my_xml_loader.addEventListener(Event.COMPLETE, processXML);
Now inside your loadImages() function we are goint to create the text field, make it say "Loading", position it, and then add it to the display list. Note that this code is made outside the loop, but yet inside the function:
for (var i:Number = 0; i < my_total; i++){
var my_url:String = my_images[i].@URL;
var my_loader:Loader = new Loader();
my_loader.load(new URLRequest(my_url));
my_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);
my_loaders_array.push(my_loader);
var my_label:TextField = new TextField();
my_label.text = my_images[i].@TITLE;
my_label.autoSize = TextFieldAutoSize.LEFT;
my_labels_array.push(my_label);
}
my_preloader = new TextField();
my_preloader.text="Loading";
my_preloader.autoSize = TextFieldAutoSize.CENTER;
my_preloader.x = (stage.stageWidth - my_preloader.width)/2;
my_preloader.y = (stage.stageHeight - my_preloader.height)/2;
addChild(my_preloader);
}
We now need to have this text field removed from the display list when the show starts:
removeChild(my_preloader);
addChild(my_slideshow);
my_slideshow.addChild(my_image_slides);
my_slideshow.addChild(my_label_slides);
nextImage();
my_timer = new Timer(my_speed*1000);
my_timer.addEventListener(TimerEvent.TIMER, timerListener);
my_timer.start();
}
That should do it. You can now have a preloader text shown as your images load.
Optimizing the Code
The slideshow should now work fine in most circumstances, however, good practice requires us to optimize the code and clean it up so that the movie works without the risk of having memory issues. We can do that by unregistering events and and deleting objects once they are no longer needed. We are going to do this step by step.
Starting from our first processXML() event listener function. Once this function is executed, there is no longer a need for the function to be registered with our instance of the URLLoader nor there is any need for the instance of the URLLoader itself as all the data we need is stored in separate variables. We can unregister the event by using the removeEventListener() method and we can delete an instance by setting its value to null:
var my_xml:XML = new XML(e.target.data);
my_speed=my_xml.@SPEED;
my_images=my_xml.IMAGE;
my_total=my_images.length();
loadImages();
my_xml_loader.removeEventListener(Event.COMPLETE, processXML);
my_xml_loader = null;
}
Moving on to the image loading process, the onComplete event listener function is also no longer needed once each image is loaded. In order to unregister this event listener we need to retrieve a reference for our LoaderInfo object and use the removeEventListener() method with it.
my_success_counter++;
if (my_success_counter == my_total){
startShow();
}
var my_loaderInfo:LoaderInfo = LoaderInfo(e.target);
my_loaderInfo.removeEventListener(Event.COMPLETE, onComplete);
}
Finally, due to AS3 unpredictable garbage cleaning process, Tween Class animations which are not referred using any permanent reference might be deleted randomly in some browsers. To ensure that this doesn't happen to our tweens we can use an array to save references to our tweens.
Start off by creating a new array at the top of your code:
var my_total:Number;
var my_images:XMLList;
var my_loaders_array:Array = [];
var my_labels_array:Array = [];
var my_success_counter:Number = 0;
var my_playback_counter:Number = 0;
var my_slideshow:Sprite = new Sprite();
var my_image_slides:Sprite = new Sprite();
var my_label_slides:Sprite = new Sprite();
var my_preloader:TextField;
var my_timer:Timer;
var my_prev_tween:Tween;
var my_tweens_array:Array = [];
var my_xml_loader:URLLoader = new URLLoader();
my_xml_loader.load(new URLRequest("slideshow.xml"));
my_xml_loader.addEventListener(Event.COMPLETE, processXML);
We are now going to store all of our tweens in specific positions in this array. Start by updating the nextImage() function this way:
var my_image:Loader = Loader(my_loaders_array[my_playback_counter]);
my_image_slides.addChild(my_image);
my_image.x = (stage.stageWidth - my_image.width)/2;
my_image.y = (stage.stageHeight - my_image.height)/2;
my_tweens_array[0] = new Tween(my_image,"alpha",Strong.easeOut,0,1,1,true);
var my_label:TextField = TextField(my_labels_array[my_playback_counter]);
my_labels_slides.addChild(my_label);
my_label.x = my_image.x;
my_label.y = my_image.y + my_image.height;
my_tweens_array[1] = new Tween(my_label,"alpha",Strong.easeOut,0,1,1,true);
}
And the final step is in updating the hidePrev() function in the same way:
var my_image:Loader=Loader(my_image_slides.getChildAt(0));
my_prev_tween = new Tween(my_image,"alpha",Strong.easeOut,1,0,1,true);
my_prev_tween.addEventListener(TweenEvent.MOTION_FINISH, onFadeOut)
var my_label:TextField=TextField(my_label_slides.getChildAt(0));
my_tweens_array[2] = new Tween(my_label,"alpha",Strong.easeOut,1,0,1,true);
}
There is no need to store the prev_tween in the array because it is already stored in a permanent variable.
Finally, we can also delete our preloader textfield when the movie starts instead of just removing it from the display list. We can do that by setting the value of that variable to null:
removeChild(my_preloader);
my_preloader = null;
addChild(my_slideshow);
my_slideshow.addChild(my_image_slides);
my_slideshow.addChild(my_label_slides);
nextImage();
my_timer = new Timer(my_speed*1000);
my_timer.addEventListener(TimerEvent.TIMER, timerListener);
my_timer.start();
}
That should do it. Your slideshow is now fully functional and optimized!
This concludes our tutorial. I hope that you learnt something new from it. You can download the end source file from here. Feel free to post any questions you have at the Republic of Code Forum.
- End of Tutorial.
