Amen is an industrial informatics engineer. he studied the first four years of his education in Faculty of Engineering in Lebanon. He went to France to Continue his studies by doing the fifth year of engineering and the master TIS (Technologie Information et Système) in the same time at UTC (Université de Technologie de Compiègne). He also work as a freelancer in flash development field. He is always interessted in the new multimedia technologies.
Time: 40 minutes
Difficulty Level: Intermediate
Requirements: Flash CS3
in this tutorial you will learn how to create a smooth Photo Viewer, with an xml file to feed our application.
We will cover
In this tutorial we will create an Action Script 3 photo viewer we will go through the xml in AS3 which will hold our photo links to generate our photo viewer data. Let’s take a look at the result we will be ended with.
Ok, let’s go through our xml file structure on the next page.
Our XML structure is actually pretty simple we have a root tag which named images and the sub items are named img and each one will contain the url to the images we need to load.
[code]
<images>
<img> url1 </img>
<img> url2 </img>
</images>
[/code]
To load an external file in AS3 we need to create a URLLoader object and a URLRequest object. Our xml file is named “data.xml” and the instance of the URLLoader object is called xmlLoader then all we have to do is to use the load method with the URLRequest object to load the xml file.
xmlLoader.load(new URLRequest("data.xml"));
What we need after this is to assign a load complete event which will be triggered after the loading of the xml has done.
xmlLoader.addEventListener(Event.COMPLETE,parseXML);
The parseXML is the method which will be executed asynchronously after the xml loading is done.
The call back function is in our public class that is assigned to our stage movie.
Private function parseXML(event){
//the event object contain our xml data in a string format, we will create our xml object from it
myXML:XML=new XML(event.target.data);
}
Event.target represent the URLLoader Object and the data proporety contain the loaded file data in a string fromat.
So after the loading let's do the parsing and the menu generation.
This class that extends the Sprite Class will holds the bitmap data of an image loaded (we will see how the bitmap data is retrieved in the next page) and it will also create the reflection of the image dynamiclly.
Class Code
[as]//class to display a bitmap data with reflexion
class ImageContainer extends MovieClip {
//bitmap object
private var bmp:Bitmap;
//reflection bitmap object
private var reflexion:Bitmap;
//ref bitmap data
private var refData:BitmapData;
//reflextion mask
private var refmask:Sprite;
public function ImageContainer() {
//initialize the bmp and the reflexion object
bmp=new Bitmap();
reflexion=new Bitmap();
//and add it to the image container
this.addChild(bmp);
}
//setter for the bitmap data
public function set imageData(value:BitmapData) {
//if the old value is not null dispose the data
if (bmp.bitmapData!=null) {
bmp.bitmapData.dispose();
}
//set the new data
bmp.bitmapData=value;
//update the position
reflexion.x=bmp.x=-bmp.width/2;
bmp.y=-bmp.height/2;
//flip the reflexion object
reflexion.scaleY=-1;
//force the smoothing
bmp.smoothing=true;
//create the reflextion bitmap data
refData=new BitmapData(bmp.width,bmp.height/4);
//and copy the pixel for the bmp bitmapdata
refData.copyPixels(bmp.bitmapData,new Rectangle(0,3*bmp.height/4,bmp.width,bmp.height/4),new Point(0,0));
//set the bitmap objects bitmap data
reflexion.bitmapData=refData;
//set the smoothing to true
reflexion.smoothing=true;
//update the reflextion position
reflexion.y=bmp.height/2+reflexion.height+5;
//create the mask
refmask=new Sprite();
//fill it with a gradient color (see help files)
var fillType:String = GradientType.LINEAR;
var colors:Array = [0xFFFFFF, 0xFFFFFF];
var alphas:Array = [0.5, 0];
var ratios:Array = [0x00, 0xFF];
var matr:Matrix = new Matrix();
matr.createGradientBox(reflexion.width, reflexion.height, Math.PI/2, 0, 0);
var spreadMethod:String = SpreadMethod.PAD;
refmask.graphics.beginGradientFill(fillType, colors, alphas, ratios, matr, spreadMethod);
refmask.graphics.drawRect(0,0,reflexion.width, reflexion.height);
//see help files
//update the ref mask postion
refmask.x=reflexion.x;
refmask.y=reflexion.y-reflexion.height;
//cash as bitmap both the relexion mask and reflexion sprite
refmask.cacheAsBitmap=true;
reflexion.cacheAsBitmap=true;
//set the mask on the reflextion
reflexion.mask=refmask;
//add the mask
addChild(refmask);
this.scaleX=1;
this.scaleY=1;
//add reflexion
addChild(reflexion);
}
}[/as]
In the next page we will examin the loading of the images one after another.
Ok so at this point we need to load the images resize it and retrieve the bitmapdata from it and then provide this data to a new ImageContainer Object. first of all we load the image in the loader Object, the loader object is added to the fakeHolder instance, after the loading of an image is done we use a resize function to resize the image with no distortion of its ratio, depending on the stage size, after the resizing we retrieve our bitmap date from the fakeHolder which is not resized by the way the loader instance is the one that is resized so the data u retrieve is for the resized image (less bitmapdata).
Loading Code
[as]//load the images via this function
private function loadNextImage(){
//Trivial Test to stop the loading
if(imgPos==imgTotal){
return;
}
//get the url
var url:String=xmlList[imgPos].toString();
//assign it to the urlRequest objecct
urlRequest.url=url;
//load it
loader.load(urlRequest)
}[/as]
the xmlList contain the list of our items each item have the url we retrieve it from it give it to the urlRequest and then loaded using the loader object.
OnImage Loaded Code
[as]private function onImageLoaded(event:Event) {
trace('onImageLoaded');
//fix the size of the loaded which is inside the fakeHolder
fixSize(loader);
//create a new bitmap data
myBitmapData= new BitmapData(loader.width, loader.height);
//draw it from the fakeHolder to retrieve the data of the resized image
myBitmapData.draw(fakeHolder);
//creata a new image container
var imgContainer:ImageContainer=new ImageContainer();
imgContainer.imageData=myBitmapData;
//set its position
imgContainer.x=stageW*(imgPos)+imgPos*stageW/2;
//add it to the image holder
imgHolder.addChild(imgContainer);
//and to the reference array
item_array.push(imgContainer);
//update the image position
imgPos++;
//triger the onAllImagesLoaded event
if(imgPos>=imgTotal){
onAllImagesLoaded();
return;
}else{
//or load the next image
loadNextImage();
}
}[/as]
as u can see the fixSize function is called before retrieving the bitmap data.
Resizing Function
[as]private function fixSize(loader:Loader) {
var sw:Number=1;
var sh:Number=1;
loader.scaleX=1;
loader.scaleY=1;
//depending on the stageW and stageH and without loosing the ratio
//the loaded is resized
if (loader.width>stageW) {
sw=stageW/loader.width;
}
if (loader.height>stageH) {
sh=stageH/loader.height;
}
var s:Number=Math.min(sw,sh);
loader.width*=s;
loader.height*=s;
}[/as]
the first 2 vars are the ratios setted to 1, reinit the loader scale (because we use only one loader), compare the size of the loader with the stage size and the ratio is the minimum between them.
Now let's check the transitions function on the next page
Now we assign to the holder of all the images an ON_ENTERFRAME event and in it we perform some calculation to update the holder and the imgHolder postion and scale to have a nice transition between the images.
Code
[as]
private function dispatchOnEnterFrame(e){
//if the diffrence=0 do nothing
if(diffX==0)return;
//else update the sliding of our image holder with easing
imgHolder.x+=(finalX-imgHolder.x)/6;
//and also update the current X aside but with a greater easing coef to have some retard in time
//between the 2 transition
cX+=(finalX-cX)/12;
//generate a percentage
var per=100*(1-(finalX-cX)/diffX);
//and ease the current percentage depending on the current generated percentage
//this will assure the smoothing and the continus animation
percentage+=(per-percentage)/12;
//update the scaling to have the zoom in out effect
holder.scaleX=1-(.5)*Math.sin(Math.PI*percentage/100);
holder.scaleY=1-(.5)*Math.sin(Math.PI*percentage/100);
}
[/as]
first of all if the difference between the selected image and the position of the imgHolder which is a child of the holder and contain the images IS Zero then do nothing. else we perform the easing Out equation on the imgHolder we also do the same think on a fake variable called cX the current is but with a greater coef to have the same result but in a slower time after this we calculate the percentage in an easing Out equation too, so we never have a discontinuty in our transition and at the end we update the scale wich goes between 1 if the percentage is 0 or 100 and min .5 if the precentage is 50.
all the rest in the class of our movie is some basic stuff like the drawing of the background function and the ON_CLICK event of the menuItems. If you have any questions regarding this please go to the forums.
Thanks for reading, the files are attached below. Have fun ;)