In this tutorial we will create something like this. (click on the picture to see a demo)
For this tutorial we will use Flash Builder 4.5 and we are going to learn how to import images from an XML file, make a smooth looking transition between each image, use the GreenSock Tweening Platform for animation and its loader class to import the data from the xml and how to import an SWC file in Flash Builder 4.5 so we can use its code hinting.
The first thing we should do if we are using Quicksilver in Macintosh and we have ” control + SpaceBar ” as a HotKey is to change the Content Assist Binding Key to something different in the Flash Builder 4.5 Preferences
(click for bigger picture)
Before any coding we should get the latest GreenSock Tweening Platform. This includes an amazing group of ActionScript classes that can make any hard work look easy.
Once downloaded, we can start making our flex project.
1) In Flash Builder we select File -> New -> Flex Project (as shown in the picture below)
2) In the New Flex Project Box we are going to put the project name we want. In this case we are going to call it ImageTransitions, we will use the default location of our project for the storage of the xmlx, images, xml and ActionScript files. We then select the application type, Web (runs in Adobe Flash Player) is selected by default.
If you don’t have the latest Flex SDK you can download it from the Adobe Open Source Download Site and put it in the sdks folder at the Flash Builder 4.5 installation directory. Once everything is correct we press Next.
3) In the Server Settings part we are going to leave everything as shown below (default options) and press Next.
4) In the Build Paths section is where we are going to select the SWC file that contains all the classes from GreenSock that we are going to use. We leave everything that comes as default and press Add SWC. In the box that just appeared we press Browse and we look for the SWC file that comes in the folder we downloaded previously from GreenSock. If everything is correct you should have something like the picture below. Then we click Finish to create our Flex Project.
5) In the xmlx editor we select Design
and then we add a Button from the Components panel, usually it is located at the bottom-left side of the window. On the Properties panel located at the bottom-right side of the window, we write startButton as the ID and Start as the Label. In the bottom part of the button properties we select the horizontal
middle constraint and put 0 in the corresponding Text Box as show in the pictures below.
6) Next we add the progress bar that will show the total progress of the loaded pictures before any transition. To do that we drag and drop to the stage the progressBar component and in the properties panel we put loader as the ID. To make the progressBar stay at the center of the web page, we select both the horizontal middle constraint and the vertical middle constraint and put 0 as their values.
7) The next thing we should do is to put the imageHolder and the imageMask. Lets select first the Image component and drop it to the stage, change its properties to imageHolder as the ID, both Width and Height to 400 and its constraints to 0 for the horizontal middle and vertical middle. Then we do the same to the imageMask, we select the SkinnableContainer component, drop it to the stage and change is properties to imageMask as the ID and the rest like the imageHolder so it will have the same size and it will be on top covering it.
8) Now that we have the startButton, the loader, the imageHolder and the imageMask on the web page. We need to add the click behavior to the button so we can start loading the images and animating the transitions. To do this we select the startButton from the design window and in its properties on the right of the On click input text, we click the little thunder icon and select Generate Event Handler. Then it automatically redirects us to the Source window.
9) The next thing we should do before any coding is to add mode="manual" in the progressBar properties and change <s:Image to <mx:Image like the picture below.
10) Now we are ready to start coding. first we are going to need a timer so the transitions cycle automatically. To do this we make a Timer variable.
private var transitionTimer:Timer = new Timer(5000);
We put 5000 because it is 5 seconds but in milliseconds, if we want the timer to wait more or less before any action we change this value.
11) Next we want to add the XMLLoader Class from GreenSock to import an xml file we will later create. So we add this line of code.
private var galleryLoader:XMLLoader = new XMLLoader("xml/images.xml", {name:"imagesXML", maxConnections:1, estimatedBytes:1000000, onComplete:galleryLoaderCompleteHandler, onProgress:galleryLoaderProgressHandler, onChildComplete:imageCompleteHandler});
The parameters to initialize the XMLLoader are:
1) The first parameter is a String of the path of the xml: in this case we are telling to the XMLLoader to search for the file in the xml folder. Right now we don’t have neither the xml file nor the folder but we will add them later.
2)The second parameter is an Object. In this object we are passing the name of the file we want, the maximum number of simultaneous connections that should be used while loading the child loaders that had their load attribute set to “true”, the default is 2 but for this tutorial we will put 1 to see how it handles its loading, the estimatedBytes of the total of the child loaders, the onComplete method we are going to use, the onProgress method for when the loading is taking place and finally the onChildComplete that is dispatched every time a child is loaded successfully.
If we want to import XMLLoader Class automatically we should use the Content Assist when we are writing the code like the picture below.
12) Then we are going to write the functions for the XMLLoader we had just created.
The first one is the galleryLoaderCompleteHandler function. Every function in that was passed in the XMLLoader Constructor receives a LoaderEvent object. We should use again the Content Assist while writing the code so the appropriate import is created automatically.
This function will fire only when everything has loaded successfully so we will want to hide the loader, and if the timer we created previously is not running we make it start. Also at this point we will call a function called changeImage() that later we are going to write.
private function galleryLoaderCompleteHandler(event:LoaderEvent):void {
loader.visible = false;
if(!transitionTimer.running) {
changeImage();
transitionTimer.start();
}
}
Now we write the code for the galleryLoaderProgressHandler and for the imageCompleteHandler.
In the galleryLoaderProgressHandler we make our loader to match the progress of the loading event. To make this happen we use the setProgress function. This function receives 2 parameters, the first one is the actual value of the progress and the second one is the total. So for example if we pass 0.5 as the first parameter and 1 as the second, the result will be a 50% loaded bar. In this case we use 1 as the total because the progress property from the event.target from the GreenSock LoaderEvent Class is a value from 0 to 1.
private function galleryLoaderProgressHandler(event:LoaderEvent):void {
loader.setProgress(event.target.progress, 1);
}
In the imageCompleteHandler we will add the loaded image to our imageHolder. First we are going to need a variable to hold the image. So we create a instance of a ContentDisplay class because the content property of the ImageLoader class that will contain the image is a Sprite. Then we make that image transparent with the alpha property, and finally we add that image to our imageHolder through the addChild function. Again we should use the Content Assist so the ContentDisplay import is added.
private function imageCompleteHandler(event:LoaderEvent):void {
var loadedImage:ContentDisplay = event.target.content;
loadedImage.alpha = 0;
imageHolder.addChild(loadedImage);
}
13) Now we go to our button click handler (startButton_clickHandler) so we can add the code to disable the button once it is clicked, start loading the images and create the listener for the transitionTimer variable.
To disable the button we use the enabled property and assign it to false. Then we call the load function from the galleryLoader variable and finally we add en event listener to the transitionTimer.
To add an event listener we use the function addEventListener, which receives 2 parameters, the first one is a String containing the type of the event, and the second one is the function who will take care of the event.
protected function startButton_clickHandler(event:MouseEvent):void
{
startButton.enabled = false;
galleryLoader.load();
transitionTimer.addEventListener(TimerEvent.TIMER, runMany);
}
14) At this part we need to tell the LoaderMax class to activate the ImageLoader class so the galleryLoader can parse automatically its contents and if there is any ImageLoader node to transform it to an object. This code should come before the variables declaration and after the import section.
LoaderMax.activate([ImageLoader]);
If we use the Content Assist the imports for the LoaderMax and ImageLoader classes will be added.
15) Then we create the runMany function that will fire every 5 seconds and the changeImage function that will animate the images and change its indexes.
This function receives an TimerEvent object as a parameter.
private function runMany(event:TimerEvent):void {
changeImage();
}
In the changeImage function we cycle through all the children in the imageHolder component (all the images) and we check if we are in the highest depth (last index). If we are not in the last children of the component we change its index to the next one using the setChildIndex function and passing 2 parameters, the first one is the object we want to change and the second one is the new index we want. Doing this guarantees that the bottom image is going to be shown on top of the others each time this function is called. Next we use a TweenMax animation (we could also use TweenLite this time because we are only changing the alpha property) to change the alpha property to 0. This means that all the images that are not in the highest position will not be shown.
The to function of TweenMax class receives 3 parameters, the first one is the object we want to tween, the second one is the duration in seconds (or in frames for frame-based tweens) and the third one is a vars object containing the end values of the properties we want to tween.
In the else part we are going to tell which object is going to be the mask of the highest position child of the imageHolder. And then we use the same TweenMax alpha animation but change the value to 1.
private function changeImage():void {
for(var i:Number = 0; i<imageHolder.numChildren; i++) {
if(i < (imageHolder.numChildren - 1)) {
imageHolder.setChildIndex(imageHolder.getChildAt(i), (i + 1));
TweenMax.to(imageHolder.getChildAt(i), 1, {alpha:0});
} else {
imageHolder.getChildAt(i).mask = imageMask;
TweenMax.to(imageHolder.getChildAt(i), 1, {alpha:1});
}
}
}
16) We now have to create the folder for the images, the xml file and the class for the mask we are going to use. To create a package we select the src folder in the Package Explorer, Right Click -> New -> Package.
In the New Package box we leave the Source path to the default location and we write images in the Name input text box.
Now we have to go to our Project Location (the one we left as default when we created our project) and paste some images. In the Package Explorer we should get something like the second picture.
Then we create another package but we are going to name it this time xml and in the Package Explorer we select it, Right Click -> New -> Other. In the Wizard Box we type xml, select XML File, press Next, write images.xml as its name and press Finish.
17) Right now a new Editor Window should open. Be sure to select Source at the bottom of the window.
Then we create a data node that will contain all the images. Each image node will be an ImageLoader so we can tell where is the image and how we want to show it.
The first attribute we are using is the name, we can put any name we want. The second property is the url, that is the location of the image we want to show, in this case it is in the folder images with the name image1.jpg. The third one is the estimatedBytes, this will help the loading progress to be more accurate. The fourth one is the load attribute which will tell the ImageLoader class to automatically load the content to the container, then we have the width and height that should be the same width and height that the imageHolder component. And finally the scaleMode attribute. This time we will use porportionalInside because we want the image to be scaled within the width and height properties.
<data>
<ImageLoader name="image1" url="images/image1.jpg" estimatedBytes="86000" load="true" width="400" height="400" scaleMode="proportionalInside"/>
<ImageLoader name="image2" url="images/image2.jpg" estimatedBytes="233000" load="true" width="400" height="400" scaleMode="proportionalInside"/>
<ImageLoader name="image3" url="images/image3.jpg" estimatedBytes="176000" load="true" width="400" height="400" scaleMode="proportionalInside"/>
<ImageLoader name="image4" url="images/image4.jpg" estimatedBytes="82000" load="true" width="400" height="400" scaleMode="proportionalInside"/>
</data>
18) Then we have to create out transition mask class. To do this we select the default package in the Package Explorer panel, Right Click -> New -> ActionScript Class. We name it CustomMask and press Finish.
19) Now we have to write the code for our CustomMask. Before the constructor we put out class variables. we are going to need the number of lines or bars that the mask will have.
private var _lines:Number = 25;
The constructor of our CustomMask class should receive 1 parameter (the SkinnableContainer we named imageMask at the beginning) so we add that part of the code. Using the Content Assist should put all the imports needed.
Next, we cycle through the number of lines or bars we are going to draw and create a new SpriteVisualElement, change the x property to the end of the next bar. Use the graphics property to draw the rectangle. The drawRect function receives 4 parameters, the first is the x position, the second is the y position, the third is the width of the rectangle and the last one is the height of the rectangle. We put the alpha property to 0 because we don’t want to show the mask before any masking occurs. Then we add the rectangle to the imageMask received through the constructor with the addElement function.
public function CustomMask(imageMask:SkinnableContainer)
{
for(var i:Number = 0; i < _lines; i++) {
var sprite:SpriteVisualElement = new SpriteVisualElement();
sprite.x = imageMask.width/_lines * i;
sprite.graphics.lineStyle(0,0xFFFFFF);
sprite.graphics.beginFill(0x000000);
sprite.graphics.drawRect(0, 0, imageMask.width/_lines, imageMask.height);
sprite.graphics.endFill();
sprite.alpha = 0;
imageMask.addElement(sprite);
}
}
If everything is correct we should have something like this.
Lets save the Class by pressing Cmd+S on Macintosh or Ctrl+S on Windows, and then add the mask code to the ImageTransitions.mxml file.
20) In the ImageTransitions.mxml Editor we have to add 2 more variables. One will be a TimelineMax object from GreenSock and the other one will be the CustomMask object we just created. Again, using the Content Assist will put all the necessary imports.
We don’t need to initialize this variables right now because we will do it later in the code.
private var imageTL:TimelineMax;
private var customMask:CustomMask;
In the startButton_clickHandler function we have to add this line of code at the end.
customMask = new CustomMask(imageMask);
And we have to edit the changeImage function to make it look like this.
private function changeImage():void {
imageTL = new TimelineMax();
for(var i:Number = 0; i<imageHolder.numChildren; i++) {
if(i < (imageHolder.numChildren - 1)) {
imageHolder.setChildIndex(imageHolder.getChildAt(i), (i + 1));
TweenMax.to(imageHolder.getChildAt(i), 1, {alpha:0});
} else {
imageHolder.getChildAt(i).mask = imageMask;
TweenMax.to(imageHolder.getChildAt(i), 1, {alpha:1});
}
}
for(i=0; i<imageMask.numElements; i++) {
imageTL.insert(TweenMax.to(imageMask.getElementAt(i), 1, {scaleX:1, startAt:{scaleX:0}}),0);
}
imageTL.play();
}
We are creating a new TimelineMax animation that will hold all the animations of each of the children of the imageMask component. We use a TimelineMax variable because we want all of the animations of each bar in the mask to start at the same time, that is why we use the function insert, that receives a TweenMax or TweenLite object and the start position of the animation.
If everything is correct we should have this imports at the beginning.
import com.greensock.TimelineMax;
import com.greensock.TweenMax;
import com.greensock.events.LoaderEvent;
import com.greensock.loading.ImageLoader;
import com.greensock.loading.LoaderMax;
import com.greensock.loading.XMLLoader;
import com.greensock.loading.display.ContentDisplay;
And now where are ready to save and then run our project by clicking this icon. ![]()
Here are the source files of the Flex Project for download.































