1. Code
  2. Coding Fundamentals
  3. Game Development

Build a Photo Viewer Using Flex and the Flickr API

Scroll to top

In this tutorial you will learn how to use the as3flickrlib library to create a Flash Flickr photo viewer.

Step 1: The as3flickrlib

There are many libraries available for Flex developers that interface with Flickr. The as3flickrlib library was created by Adobe and is the library that we'll use to create this photo viewing application. You'll need to download a copy of the as3flickrlib code for yourself, as well as the as3corelib library (as3flickrlib depends on as3corelib). Both can be obtained from here.

Step 2: TweenMax

You'll also need the TweenMax library. TweenMax is a tweening library, which allows us to easily change the properties of an object over time. You can get TweenMax here.

Step 3: New Project

Create a new Flex web project and add the three libraries mentioned above to the Source Path of the application.

Step 4: Wrapper Class

This application works by taking the images loaded from Flickr and adding them to the main Application object (i.e. the object that is created by the MXML file). When you load an image off the web it is returned to you as a Bitmap. While the Bitmap class extends the DisplayObject class (which is what the addChild function requires), Flex will only allow those classes that extend the UIComponent class to be added as a child of the main Application object, and the Bitmap does not extend the UIComponent. The compiler will not flag adding a Bitmap to the Application object via the addChild function as an error, but you will get an exception at run time.

Still, it would be nice to be able to add the Bitmap objects as children of the Application object. We need to create a small wrapper class that does extend the UIComponent class (so it can be added to the Application), but also adds a Bitmap as a child of itself. That wrapper class is called DisplayObjectUIComponent.

1
2
package
3
{
4
	import flash.display.DisplayObject;
5
	
6
	import mx.core.UIComponent;
7
	
8
	public class DisplayObjectUIComponent extends UIComponent
9
	{
10
		public function DisplayObjectUIComponent(displayObject:DisplayObject)
11
		{
12
		    super ();
13
		
14
		    explicitHeight = displayObject.height;
15
		    explicitWidth = displayObject.width;		
16
		    addChild (displayObject);
17
		}
18
	}
19
}

Step 5: New MXML File

Now we need to create the MXML file.

1
2
<?xml version="1.0" encoding="utf-8"?>
3
<mx:Application 
4
  xmlns:mx="<a href="http://www.adobe.com/2006/mxml">http://www.adobe.com/2006/mxml</a>" 

5
  layout="absolute" 
6
  backgroundGradientAlphas="[1.0, 1.0]" 
7
  backgroundGradientColors="[#000000, #5B5B5B]" 
8
  creationComplete="onComplete()">
9
  
10
  ...
11
  
12
</mx:Application>

This is the shell of the MXML file. Most of the code is the same as the empty template that is created when you open up a new Flex application in Flex Builder. In addition we've specified the background colors (with the backgroundGradientAlphas and backgroundGradientColors attributes) and set the onComplete function to be called when the Application object has created itself (with the creationComplete attribute).

Step 6: mx:script Tag

The code that will do the job of downloading and displaying the Flickr images needs to be contained in an mx:script tag. The <![CDATA[ ... ]]> tag just allows us to write code without having to worry about special characters like greater-than and less-than (< and >) being interpreted as part of the XML document.

1
2
<mx:Script>
3
  <![CDATA[
4
5
  ...
6
7
  ]]>
8
</mx:Script>

Step 7: Import Classes

We need to import some classes for use within our application.

1
2
import mx.collections.ArrayCollection;
3
import mx.controls.Alert;
4
import com.adobe.webapis.flickr.*;
5
import com.adobe.webapis.flickr.events.*;
6
import gs.TweenMax;
7
import gs.easing.*;

Step 8: Define Constants

Next we need to define some constants that will control how our application works.

1
2
private static const SEARCH_STRING:String = "sunset";
3
private static const MAX_RESULTS:int = 50;
4
private static const API_KEY:String = "your key goes here";
5
private static const TRANSITION_TIME:Number = 1;
6
private static const DISPLAY_TIME:Number = 3;
  • SEARCH_STRING defines the query that will be sent to Flickr. In essence we'll be querying Flickr for images much like you would query Google for web pages. We have set the query to "sunset" here, but this string could be anything like "kittens", "mountains", "cars" etc.
  • MAX_RESULTS defines how many images Flickr will return once it has been queried.
  • API_KEY is your own Flickr API key, which you can apply for here.
  • TRANSITION_TIME defines how quickly the images will fade into each other in seconds. Here we've set the transition time to take 1 second.
  • DISPLAY_TIME defines how long each image will be displayed before the next image is loaded. Here we've set each image to be displayed for 3 seconds.

Step 9: Define Variables

We need to define a few variables for our application.

1
2
private var photos:ArrayCollection = null;
3
private var currentImage:int = 0;
4
private var displayImage:Bitmap = null;
5
private var backgroundImage:Bitmap = null;
  • The photos variable is a collection of the photo definitions sent back by Flickr. It's important to note that Flickr does not actually send back the photos themselves, but only the information needed to find the URL of the photo, which then has to be downloaded separately.
  • The currentImage variable maintains an index in the photos collection. This is so we know what photo needs to be displayed next.
  • The displayImage and backgroundImage variables are references to the Bitmap objects that are created by loading the Flickr images.

Step 10: Policy Files

By default a Flash application can only load resources from it's own domain. In order to load resources from another domain (like Flickr) the owner of that domain needs to have a policy file, usually called crossdomain.xml, that lets the Flash runtime know that it's OK to load their resources. This policy file needs to be loaded before any attempts are made to load the resources.

Flickr hosts it's images on a number of servers, so here we load the policy file of these servers. If you don't perform this step you'll get an exception when trying to load images off these domains.

1
2
Security.loadPolicyFile("http://farm1.static.flickr.com/crossdomain.xml");
3
Security.loadPolicyFile("http://farm2.static.flickr.com/crossdomain.xml");
4
Security.loadPolicyFile("http://farm3.static.flickr.com/crossdomain.xml");
5
Security.loadPolicyFile("http://farm4.static.flickr.com/crossdomain.xml");

Step 11: onComplete Function

When the Flex application has finished creating itself, the onComplete function will be called (this is what we specified in Step 5). The onComplete
function is the entry point of the application.

1
2
private function onComplete():void
3
{
4
	var service:FlickrService = new FlickrService(API_KEY);
5
	service.addEventListener(FlickrResultEvent.PHOTOS_SEARCH, onPhotosSearch);
6
	service.photos.search("", SEARCH_STRING, "any", "", null, null, null, null, -1, "", MAX_RESULTS, 1);
7
}

The first thing we need to do is create a new instance of the FlickrService class. The FlickrService object is our gateway to Flickr, and we use that to submit our search for our sunrise images. You need to supply the Flickr API key (from Step 8) to the FlickrService constructor.

1
var service:FlickrService = new FlickrService(API_KEY);

Next we attach a function to the FlickrResultEvent.PHOTOS_SEARCH event. This function will be called when Flickr has returned some information about a search. Here we attach the onPhotosSearch function.

1
service.addEventListener(FlickrResultEvent.PHOTOS_SEARCH, onPhotosSearch);

Finally we perform the actual search itself. The search function has a lot of parameters that can be used to narrow a search down to a specific user, date, title and more. We're only interested in finding photos with the tag sunset, and so supply either a null, empty string or -1 to these other parameters.

1
service.photos.search("", SEARCH_STRING, "any", "", null, null, null, null, -1, "", MAX_RESULTS, 1);

Step 12: onPhotoSearch Function

The onPhotoSearch function is called when Flickr has returned some information about our search.

1
private function onPhotosSearch(event:FlickrResultEvent):void 
2
{
3
	if (event.success)
4
	{
5
		var photoList:PagedPhotoList = event.data.photos;
6
		photos = new ArrayCollection( photoList.photos );
7
		loadNextImage();
8
	}
9
	else
10
	{
11
		Alert.show("Flickr call failed. Did you update the API Key?");
12
	}
13
}

We first need to determine if the call to Flickr was successful. This is done by checking the event.success flag. If this is true Flickr has successfully returned some information about the photos we queried it for. If event.success is false then the call failed. This usually happens because the API key that was supplied was incorrect.

1
2
if (event.success)
3
{
4
	...
5
}
6
else
7
{
8
	...
9
}

If the call was successful we need to get access to the collection of photo data that was returned.

1
var photoList:PagedPhotoList = event.data.photos;

The PagedPhotoList then contains the details of the photos themselves, which we then save in the photos collection.

1
photos = new ArrayCollection( photoList.photos );

At this point the photos collection contains a list of photo details which can then be used to load the actual photo images. From here on in we'll just be downloading images, from the URLs we created using the information in the photos collection, without any more special calls using the Flickr API.

To start the photo album, we need to call the loadNextImage function.

1
loadNextImage();

If there was a problem calling Flickr the user is notified with an Alert window.

1
Alert.show("Flickr call failed. Did you update the API Key?");

Step 13: loadNextImage Function

Now that we have the details of the photos that relate to our search, we need to actually download the images so they can be displayed. This is done by the loadNextImage function.

1
2
private function loadNextImage():void
3
{
4
	var imageURL:String = 'http://static.flickr.com/' + photos[currentImage].server + '/' + photos[currentImage].id + '_' + photos[currentImage].secret + '_m.jpg';
5
6
	++currentImage;
7
	currentImage %= photos.length;
8
9
	var request:URLRequest = new URLRequest(imageURL);
10
	var loader:Loader = new Loader();
11
	loader.contentLoaderInfo.addEventListener(Event.COMPLETE, switchImages);
12
13
	loader.load(request); 
14
}

Remember that I said that the call to Flickr does not actually return the images themselves? What it does return is the information needed to
construct the URL that we can use to download the image. By using the server, id and secret information of the photos we can create the full URL that will display the image.

Each image has a number of resolutions. We pick which size image we are downloading by the suffix of the url. The _m suffix indicates that we are
downloading a medium sized version of the image. Other suffixes can be found here, which allows you to download more or less detailed versions of the images.

1
var imageURL:String = 'http://static.flickr.com/' + photos[currentImage].server + '/' + photos[currentImage].id + '_' + photos[currentImage].secret + '_m.jpg';

Now that we've requested the image, we increment the currentImage variable so the next time loadNextImage is called we'll pull down the next image in the search list.

1
++currentImage;
2
currentImage %= photos.length;

Next we have to actually load the images. We create a new URLRequest object (supplying the URL that we created above to the constructor), a new Loader object, and attach the switchImages function to the Loaders Event.COMPLETE event.

1
var request:URLRequest = new URLRequest(imageURL);
2
var loader:Loader = new Loader();
3
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, switchImages);

Finally, we load the image from Flickr by calling the Loaders load function.

1
loader.load(request);

Step 14: switchImages Function

The switchImages function is called when we've loaded an new image from Flickr.

1
private function switchImages(event:Event):void
2
{ 
3
	displayImage = event.currentTarget.content;
4
	displayImage.smoothing = true;
5
	displayImage.width = this.width;
6
	displayImage.height = this.height;
7
	displayImage.alpha = 0;
8
	this.addChild(new DisplayObjectUIComponent(displayImage));
9
10
	TweenMax.to(displayImage, TRANSITION_TIME, {alpha:1, ease:Linear, onComplete:imageTweenComplete});
11
	if (backgroundImage != null)
12
		TweenMax.to(backgroundImage, TRANSITION_TIME, {alpha:0, ease:Linear});
13
}

The Bitmap object that is returned by the loading process is saved in the displayImage variable.

1
displayImage = event.currentTarget.content;

This new Bitmap is then initialized so that it is smoothed (to help with the pixelization that can occur when you scale up small images), resized to fill the window, and set to be completely transparent by setting it's alpha to 0.

1
displayImage.smoothing = true;
2
displayImage.width = this.width;
3
displayImage.height = this.height;
4
displayImage.alpha = 0;

We then add the Bitmap to the Application via a new instance of the DisplayObjectUIComponent class that we described in Step 4.

1
 this.addChild(new DisplayObjectUIComponent(displayImage));

At this point we have the new image added as a child of the Application object. It isn't visible though because we've set the alpha to 0. What we want to do is fade this new image into view by increasing it's alpha value, while at the same time fading out the last image by decreasing it's alpha value. This is where the TweenMax library comes in. We make a call to the TweenMax.to function, and TweenMax then takes care of modifing the alpha values for us.

By setting the onComplete parameter to imageTweenComplete we schedule the imageTweenComplete function to be called once this tweening operation is
compete.

We do need to check if the backgroundImage variable is null because when the first image is loaded there is no existing backgroundImage that it is displaying on top of.

1
TweenMax.to(displayImage, TRANSITION_TIME, {alpha:1, ease:Linear, onComplete:imageTweenComplete});
2
if (backgroundImage != null)
3
	TweenMax.to(backgroundImage, TRANSITION_TIME, {alpha:0, ease:Linear});

Step 15: imageTweenComplete Function

The imageTweenComplete function is called when a newly loaded image has been faded into view by TweenMax.

1
private function imageTweenComplete():void
2
{ 
3
	if (backgroundImage != null)
4
	this.removeChild(backgroundImage.parent); 
5
	backgroundImage = displayImage;
6
	displayImage = null;
7
8
	TweenMax.delayedCall(DISPLAY_TIME, loadNextImage);
9
}

Once the displayImage has been faded in, the backgroundImage is removed from the application and the displayImage becomes the backgroundImage. The
displayImage is then set to null.

1
if (backgroundImage != null)
2
	this.removeChild(backgroundImage.parent); 
3
backgroundImage = displayImage;
4
displayImage = null;

We then use TweenMax to schedule a call to the loadNextImage function. This starts the cycle of loading a new image and fading it in again.

1
TweenMax.delayedCall(DISPLAY_TIME, loadNextImage);

Conclusion

Using Flickr with Flash does require a few steps, but once you get your head around the Flickr API, finding out the Flickr image URLs, loading the images from Flickr (taking the Flash security restrictions into consideration) it's then quite easy to use these images to create an appealing photo album.

This particular example could be used to add an animated photo album to a web page, and by changing the SEARCH_STRING variable you can display different types of images. You could even pass FlashVars to the Flash applet to determine which images are displayed without having to recompile the application. You could also modify the service.photos.search function to return only your own photos, or those that you have tagged specifically.

Thanks for reading.

Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.