Creating an XML Grid Image Gallery in Flash (ActionScript 3.0) - part 2
We are going to do two main things in this section, first we will create the MovieClip container that will hold all of our thumbs, and then we will load all the thumbnail images in one go using a loop and the Loader Class.
Here is the outline of this section:
- Creating a container movie clip and positioning.
- Use a loop to load all the thumbs using the Loader Class.
Creating a Container Movie Clip for the Thumbs
It is possible to load the thumbs directly on the stage without using a container MovieClip, but we use a container movie clip to easily later manipulate all the thumbs in one go for things like positioning and registering event handlers.
We are going to break down our code into functions so that they are arranged in a logical manner. Our first function will be typed at the very bottom of all the existing code we have. Call this function createContainer:
function createContainer():void{
}
The first task for this function is to create a MovieClip container, we can simply do that by using the new keyword, but before we do that we need to create a variable to hold a reference to this MovieClip. We can't create our variable inside the function because that will make it temporary. So we need to define this variable at the top of our code outside the function to make sure that it remains for the entire show. Use the var keyword to create a variable called container_mc at top of the code along with the other variable definitions:
var columns:Number;
var my_x:Number;
var my_y:Number;
var my_thumb_width:Number;
var my_thumb_height:Number;
var my_images:XMLList;
var my_total:Number;
var container_mc:MovieClip;
We can now put a new MovieClip in this variable using our createContainer function:
function createContainer():void{
container_mc = new MovieClip();
}
We now position this MovieClip in accordance to the variables we retrieved from the XML file, namely, using the my_x and my_y properties:
function createContainer():void{
container_mc = new MovieClip();
container_mc.x = my_x;
container_mc.y = my_y;
}
We will now add this MovieClip to the display list so that any content we add to it is later will be visible:
function createContainer():void{
container_mc = new MovieClip();
container_mc.x = my_x;
container_mc.y = my_y;
addChild(container_mc);
}
Our function is now ready, but we have not actually requested its execution from any point yet! We need this function to be called when all the variables are ready and extracted from the XML file. So call the function using the () operator from within the processXML() listener function this way:
function processXML(e:Event):void {
var myXML:XML = new XML(e.target.data);
columns = myXML.@COLUMNS;
my_x = myXML.@XPOSITION;
my_y = myXML.@YPOSITION;
my_thumb_width = myXML.@WIDTH;
my_thumb_height = myXML.@HEIGHT;
my_images = myXML.IMAGE;
my_total = my_images.length();
createContainer();
}
Loading the Thumbnails
The previous section was easy, it is now time for the first tricky part of this tutorial: loading the thumbnails. We are going to put all the code relevant to this part in a separate function to make things organized. Loading images and SWF files is done in AS3 using the Loader Class. We are going to make use of a loop to create multiple instances of the Loader Class and load all the thumbnails in one go.
We are going to do this step by step, first of all, we are going to create this new function at the bottom of our existing code, we will call it callThumbs():
function callThumbs():void{
}
All of the code inside this function will be executed through a loop, We need this loop because we need to execute the same command multiple times for each and every thumbnail. The repeated code will involve (1) retrieving the URL of the thumbnail from our image XML list, (2) creating a new instance of the loader class to load the thumb URL, and (3) registering the loader with an event listener to show the image once loaded.
We will start off by creating the loop. Our loop will cycle as long as the counter i, does not exceed our total number of images:
function callThumbs():void{
for (var i:Number = 0; i < my_total; i++){
}
}
Now will retrieve the URL of the thumb and store it in a local variable called thumb_url. This variable is only used within the loop, so there is no need to create it outside. i below is used to cycle through the elements in the XML file and it retrieves the actual URL by using the @ operator to get the value of that attribute:
function callThumbs():void{
for (var i:Number = 0; i < my_total; i++){
var thumb_url = my_images[i].@THUMB;;
}
}
We will now create a new temporary instance of the Loader Class using the new keyword, and then instantly load the thumb image using the .load() method. This is pretty simple:
function callThumbs():void{
for (var i:Number = 0; i < my_total; i++){
var thumb_url = my_images[i].@THUMB;;
var thumb_loader = new Loader();
thumb_loader.load(new URLRequest(thumb_url));
}
}
Review our tutorial on using the
AS3 Loader Class to learn more about this topic.
We need to use an event listener to show the images when they are fully loaded. To do this we will register with the Event.COMPLETE to load a special listener function called thumbLoaded which we will define later. Register the event using the .addEventListener() method:
function callThumbs():void{
for (var i:Number = 0; i < my_total; i++){
var thumb_url = my_images[i].@THUMB;;
var thumb_loader = new Loader();
thumb_loader.load(new URLRequest(thumb_url));
thumb_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, thumbLoaded);
}
}
The Loader Class can only register such events through its instance of the ContentLoaderInfo Class. Review our tutorial on using the
AS3 Loader Class to learn more about this topic.
We will now create the thumbLoaded listener function at the bottom of all of our existing code. This function will add the Loader Instances of our thumbs to the container_mc MovieClip display list to make them visible:
function thumbLoaded(e:Event):void{
var my_thumb:Loader = Loader(e.target.loader);
container_mc.addChild(my_thumb);
}
e.target.loader holds a reference to the instance of the Loader Class on to which the event listener was registered to indirectly.
The type Loader "casted" on e.target.loader to override strict data-typing requirements of the Flash compiler as the data type cannot actually be determined at compile time.
Our listener function is now ready and our previous callThumbs() is also done, we need to call this function to make it execute it when needed. Call it right below the createContainer() function from within the processXML listener function at the top:
function processXML(e:Event):void {
var myXML:XML = new XML(e.target.data);
columns = myXML.@COLUMNS;
my_x = myXML.@XPOSITION;
my_y = myXML.@YPOSITION;
my_thumb_width = myXML.@WIDTH;
my_thumb_height = myXML.@HEIGHT;
my_images = myXML.IMAGE;
my_total = my_images.length();
createContainer();
callThumbs();
}
For the first time in this tutorial you can test your movie now to see a visual output! Press Ctrl+Enter to see your thumbnails loaded. Well, you are just going to see ONE thumbnail on the stage because all the thumbnails are loaded over each other because we have not repositioned them.
We are going to position these thumbnails across the grid in the next section.
Summary of this Page
- Created a MovieClip container and positioned it in accordance with the XML data.
- Create a loop to load all the thumbs using the Loader Class.
- Used an event listener to add the thumbnails to the display list only when fully loaded.
In the next section we will position our thumbs in a grid manner.
Our thumbs are all loaded over each other and cannot be seen. In this section of the tutorial we will fix that by aligning the thumbnails in a grid manner using the logic of an if conditional and a couple of variables. This section will update the code of the callThumbs() function as it is the one responsible for the loading and positioning of the thumbnails:
This section is divided into two sections:
- Positioning the thumbs horizontally.
- Converting the line of thumbs into a gird.
Positioning the Thumbs Horizontally
A grid is essentially a set of lines placed below each other, so it is easier to make one by creating a single row of thumbs and then breaking it down than trying to create a grid from scratch, and that is what we will do.
The horizontal place of an object is controlled by its .x property. We will use this property to place our thumbs next to each other. We are going to get the distance required to position each thumb by calculating the width of thumbs before it using the formulate illustrated below:
If you recall that the first element in our XML list is actually as position zero (and our loop counter i starts counting from zero as well), and that the width of each thumb is equal to my_thumb_width then this means that we can multiply the my_thumb_width by i to get the right position for our current thumb in the loop. We write that in code this way:
function callThumbs():void{
for (var i:Number = 0; i < my_total; i++){
var thumb_url = my_images[i].@THUMB;;
var thumb_loader = new Loader();
thumb_loader.load(new URLRequest(thumb_url));
thumb_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, thumbLoaded);
thumb_loader.x = my_thumb_width*i;
}
}
You can now test your movie (Ctrl+Enter) to see that all your thumbs are now aligned horizontally.
We are going to add some spacing to these images by adding a spacing value to the width before we multiply it. Update the last line we wrote as shown below:
function callThumbs():void{
for (var i:Number = 0; i < my_total; i++){
var thumb_url = my_images[i].@THUMB;;
var thumb_loader = new Loader();
thumb_loader.load(new URLRequest(thumb_url));
thumb_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, thumbLoaded);
thumb_loader.x = (my_thumb_width+10)*i;
}
}
Again, you can test your movie again to see your thumbs spaced out.
We now have our thumbs aligned horizontally. We will next convert this into a grid layout.
Creating the Gird
When you create a grid layout you count the images horizontally until you reach the end of the row and then you go down and start all over again until you reach the same number, and just repeat:
Currently, our code counts forwards forever and does not stop to start all over. The counter variable that we use in our code is i as you have seen and we cannot change the value of this one the go because it also refers to the number item in the XML list. We need to create another counter variable which we will call x_counter to take care of the positioning instead of relying on i alone. Define this variable at the top of the code and assign the value Zero as its initial value:
var columns:Number;
var my_x:Number;
var my_y:Number;
var my_thumb_width:Number;
var my_thumb_height:Number;
var my_images:XMLList;
var my_total:Number;
var container_mc:MovieClip;
var x_counter:Number = 0;
Then replace the width multiplier with x_counter instead of i in the callThumbs() loop:
function callThumbs():void{
for (var i:Number = 0; i < my_total; i++){
var thumb_url = my_images[i].@THUMB;;
var thumb_loader = new Loader();
thumb_loader.load(new URLRequest(thumb_url));
thumb_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, thumbLoaded);
thumb_loader.x = (my_thumb_width+10)*x_counter;
}
}
We need the loop to increase the value of x_counter by 1 each time it cycles through the loop the same way i increases. We can do this by using the ++ operator this way:
function callThumbs():void{
for (var i:Number = 0; i < my_total; i++){
var thumb_url = my_images[i].@THUMB;;
var thumb_loader = new Loader();
thumb_loader.load(new URLRequest(thumb_url));
thumb_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, thumbLoaded);
thumb_loader.x = (my_thumb_width+10)*x_counter;
x_counter++;
}
}
Just as I have explained earlier, we need this counter to restart and count from zero each time it hits the end of the row. The end of the row is maximum number of columns we have in each row. We are going to update the last line we added by using a conditional to increase the value of x_counter only if x_counter is less than the number of columns, if it is not then we will reset the value of x_couner to zero.
function callThumbs():void{
for (var i:Number = 0; i < my_total; i++){
var thumb_url = my_images[i].@THUMB;;
var thumb_loader = new Loader();
thumb_loader.load(new URLRequest(thumb_url));
thumb_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, thumbLoaded);
thumb_loader.x = (my_thumb_width+10)*x_counter;
if (x_counter < columns){
x_counter++;
} else {
x_counter = 0;
}
}
}
A small problem we have with our code is that the x_counter is zero relative just like i (this means that the first item in its list is at place zero), so to actually have the number of images currently on stage we need to add 1 to it before we check if it less the number of columns. Simply update the code this way to take this into consideration:
function callThumbs():void{
for (var i:Number = 0; i < my_total; i++){
var thumb_url = my_images[i].@THUMB;;
var thumb_loader = new Loader();
thumb_loader.load(new URLRequest(thumb_url));
thumb_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, thumbLoaded);
thumb_loader.x = (my_thumb_width+10)*x_counter;
if (x_counter+1 < columns){
x_counter++;
} else {
x_counter = 0;
}
}
}
This should position your thumbs in a systematic horizontal manner, but if you have noticed we haven't said anything about the vertical position yet. You can test your movie now to see that your thumbs no longer go beyond the screen. Our line of thumbs is broken down to rows, but these rows are placed over each other.
We are going to deal with the vertical alignment now which works exactly the same way as the horizontal alignment, we are going to need a counter, and we will use the height obviously for it, but instead of increasing the counter in each loop cycle, we are only going to increase the counter only each time the x_counter is restarted. Start off by creating a new y_counter at the start of our code and set its initial value as zero.
var columns:Number;
var my_x:Number;
var my_y:Number;
var my_thumb_width:Number;
var my_thumb_height:Number;
var my_images:XMLList;
var my_total:Number;
var container_mc:MovieClip;
var x_counter:Number = 0;
var y_counter:Number = 0;
We are now going to set the y property of our thumbs by using the new multiplier and the my_thumb_height value instead of the width this time. To do this update the callThumbs() function this way:
function callThumbs():void{
for (var i:Number = 0; i < my_total; i++){
var thumb_url = my_images[i].@THUMB;;
var thumb_loader = new Loader();
thumb_loader.load(new URLRequest(thumb_url));
thumb_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, thumbLoaded);
thumb_loader.x = (my_thumb_width+10)*x_counter;
thumb_loader.y = (my_thumb_height+10)*y_counter;
if (x_counter+1 < columns){
x_counter++;
} else {
x_counter = 0;
}
}
}
Finally we now need to increase the rows only each time the x_counter is restarted, we can do this by adding a line to do this in our conditional:
function callThumbs():void{
for (var i:Number = 0; i < my_total; i++){
var thumb_url = my_images[i].@THUMB;;
var thumb_loader = new Loader();
thumb_loader.load(new URLRequest(thumb_url));
thumb_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, thumbLoaded);
thumb_loader.x = (my_thumb_width+10)*x_counter;
thumb_loader.y = (my_thumb_height+10)*y_counter;
if (x_counter+1 < columns){
x_counter++;
} else {
x_counter = 0;
y_counter++;
}
}
}
That should do it. You can test your movie now to see your thumbs aligned in a gird manner! Congratulations!
We have finished the hardest of the tutorial, but we still need to make our thumbs load the full version of themselves. That is an easy take which will take care of in the next page.
Summary of this Page
- Aligned the thumbs horizontally by using the width of previous thumbs.
- Used a counter and a conditional to restart the count once the row was filled.
- Used another counter to move the thumbs to the next row each time the horizontal counter was restarted.
In the next section we will make our thumbs load a full image of each thumb.