Final code
We’re done now. The full source code follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 | /************************************************************************************************** * AS3 SLIDESHOW v1.1 | 2008.03.30 | ©2008 MediaDivision.com * * Licensed as GNU/GPL http://www.gnu.org/copyleft/gpl.html */ package { import flash.display.*; import flash.events.*; import flash.net.*; import flash.text.*; import flash.utils.*; /** * Used to create a slideshow of dynamically loaded pictures, * based on an xml file */ public class Slideshow extends Sprite { // spacing between pics private const PIC_SPACING:int = 2; // time to display one picture private const ANIMATION_STILL_TIME:int = 4; // slide-in "braking factor"; smaller numbers result is faster braking; 1=instant braking; private const ANIMATION_SPEED_FACTOR:int = 6; // delay between animation steps in milliseconds private const ANIMATION_INTERVAL:int = 50; // randomize images in list? private const RANDOMIZE_IMAGES:Boolean = true; private var queue:Array = []; private var titles:Array = []; private var loader:Loader; private var xmlLoader:URLLoader; private var datasource:String; private var animator:Timer; private var xPos:int; private var lastTime:int; private var loadedItems:int; private var displayedItems:int; private var crtTitle:String; private var container:Sprite; private var titleField:TextField; /** * Initialize the Slideshow * @param datasouce full url of the XML containing the */ public function Slideshow(datasource:String) { container = new Sprite(); addChild(container); this.datasource = datasource; xmlLoader = new URLLoader(new URLRequest(datasource)); xmlLoader.addEventListener(Event.COMPLETE, onDataLoaded); addEventListener(Event.ADDED_TO_STAGE, onAddedToStage); } /** * Executes when the instance is actually added to Stage. * Only then we can access properties like stage.stageWidth */ private function onAddedToStage(e:Event):void { // disable stage scaling stage.scaleMode = StageScaleMode.NO_SCALE; // move container off-screen container.x = stage.stageWidth; // create the title field titleField = new TextField(); titleField.x = 0; titleField.width = stage.stageWidth; titleField.y = stage.stageHeight - 30; titleField.height = 30; titleField.selectable = false; titleField.embedFonts = true; titleField.antiAliasType = flash.text.AntiAliasType.ADVANCED; // text format for the title var format:TextFormat = new TextFormat(); //format.font = "Verdana"; // TitleFont class is created automatically by Flash CS3 IDE when you create a new Font in library // and you use the Linkage to specify a class. This way you can reference a font by class throughout // the project instead of its real name, i.e. "Futura Lt Bt" or "Century Gothic" format.font = new TitleFont().fontName; format.align = TextFormatAlign.CENTER; format.size = 20; titleField.defaultTextFormat = format; titleField.text = ""; addChild(titleField); // create the animation timer animator = new Timer(ANIMATION_INTERVAL); animator.addEventListener(TimerEvent.TIMER, animate); animator.start(); } /** * Called when the XML has loaded */ private function onDataLoaded(e:Event):void { if (!xmlLoader.data) { trace("XML Load failed"); return; } var dataXml:XML = XML(xmlLoader.data); for each (var item:XML in dataXml.item) { queue.push({url:item.@src, title:item.@title}); } if (RANDOMIZE_IMAGES) queue = shuffle(queue); loadNextItem(); } /** * Retrieves an item from the loading queue and starts loading it */ private function loadNextItem():void { // get the first item in queue var item:Object = queue.shift(); // stop when the queue is empty if (item==null) return; // keep this until the image has loaded, so we can assign crtTitle = item.title; // initialize the loader for each load request loader = new Loader(); loader.contentLoaderInfo.addEventListener(Event.INIT, onItemLoaded); loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onItemError); loader.load(new URLRequest(item.url)); } /** * Called when an image item has successfully loaded * @param e event */ private function onItemLoaded(e:Event):void { trace("loaded "+crtTitle); loadedItems++; var content:Bitmap = Bitmap(loader.content); content.x = xPos; xPos += content.width + PIC_SPACING; container.addChild(content); titles.push(crtTitle); if (queue.length > 0) loadNextItem(); else { //duplicate first and last items for wrap-around-effect var refFirst:Bitmap = Bitmap(container.getChildAt(0)); var refLast :Bitmap = Bitmap(container.getChildAt(container.numChildren-1)); // sadly, duplicateMovieClip is gone so we use this; // thank God it's not a MovieClip we needed to duplicate var copyFirst:Bitmap = new Bitmap(refFirst.bitmapData); var copyLast:Bitmap = new Bitmap(refLast.bitmapData); copyLast.x = -copyLast.width - PIC_SPACING; copyFirst.x = xPos; container.addChild(copyFirst); container.addChild(copyLast); } } /** * Called when an image item could not be loaded * Simply ignores the error and moves on * @param e event */ private function onItemError(e:Event):void { trace("load error"); loadNextItem(); } /** * Scrolls the loaded images from right to left; * If an image is not loaded, the animation will pause * Each image will stay still for a determined amount of time, displaying its title * When the slideshow reaches the end, the "strip" is wrapped around to the beginning * @param e the timer event */ private function animate(e:TimerEvent):void { // don't do anything if there isn't at least one image if (loadedItems < 1) return; // check if there is a "next" image to display if (container.numChildren > displayedItems) { var picToShow:Bitmap = Bitmap(container.getChildAt(displayedItems)); var targetX:int = stage.stageWidth/2; var itemX:int = picToShow.x + picToShow.width/2 + container.x; var delta:int = (itemX-targetX) / ANIMATION_SPEED_FACTOR; } else { // the next image hasn't loaded yet, keep showing this one var picToShow:Bitmap = Bitmap(container.getChildAt(displayedItems-1)); var delta:int = 0; } // the image has stopped... if (delta <= 0) { // the next image should be displayed... if (((getTimer()-lastTime) >= ANIMATION_STILL_TIME * 1000) && (container.numChildren > displayedItems)) { lastTime = getTimer(); displayedItems++; titleField.text = ""; } else { // we should display the title for the current image if (titleField.text == "" && titles[container.getChildIndex(picToShow)] != null) titleField.text = titles[container.getChildIndex(picToShow)]; } } // the image is still moving else { // check if we need to wrap around // conditions: we've already displayed all loaded items and the last image is now just at the left edge if ((displayedItems==loadedItems) && ((container.x + container.getChildAt(displayedItems-1).x) <= 0)) { var diff:int = 0 - (container.x + container.getChildAt(displayedItems-1).x); // seamlessly move the container back at the beginning and reset displayed images container.x = container.getChildAt(container.numChildren-1).width - diff; displayedItems = 0; } // move the container to the left container.x -= delta; } } /** * Shuffle array elements * @param arr original array * @return shuffled array */ private function shuffle(arr:Array):Array { var shuffled:Array = arr.slice(); for (var i:int=0; i < arr.length; i++) { var element:Object = shuffled[i]; var rnd:int = Math.floor(arr.length * Math.random()); shuffled[i] = shuffled[rnd]; shuffled[rnd] = element; } return shuffled; } } } |
On the next page you’ll be able to download the complete code and examples.
Improving and extending
Like I noted earlier, this Slideshow is optimized for the cases where the width of images is large enough so that 2-3 images will be displayed at any time. If the images are too narrow or too few or the Stage too wide, the slideshow may fail. By changing te rules a bit, this can be overcome.
Currently, the images flow right-to-left. It is possible to make the Slideshow scroll in both directions.
You can also add a reflective floor effect for loaded images by duplicating and mirroring each clip and applying a gradient mask to it.
Finally, and more importantly, you can add some interactivity, allowing the images to be clickable, taking you to a different URL, or maybe displaying more details.
The possibilities are endless, so have fun!
Download the code
AS3 Slideshow (148.4 KiB, 15,918 hits)
AS3 Slideshow PDF Tutorial (190.9 KiB, 5,400 hits)
I’m having a serious problem that’s just recently appeared. my flash cs3 is unable to build a classpath to the external actionscript in your tutorial example as well as others I’ve downloaded tonight. it’s driving me crazy. have you ever encountered this?
my program was corrupted. had to re-install from scratch. fine now!
thanks for this terrific example….
This was dead on and will really help out. Thanks for the time and effort to detail the code. Mahalo!
Spot on. Very useful. Thanks
This is great I’m new to actionscript and this was very helpful. It looks really nice. I was wondering, how do i go about making the images ‘clickable’?
Thanks
Excellent presentation Armand. I
Awesome flash based slide show, great work explaining it step by step as well. Thanks for sharing, keep up the good work.
Thank you very much for the tutorial, especially the pdf and full code. I linked you to where I will use it and cite for credit. Thanks!
Excellent tutorial, Armand. I will share this link with my design students. Thanks much.
This is the best tutorial/example I’ve found on the subject.
One thing you could do different is to keep the image source and title strings directly in the XML object, since it is already loaded in memory, no reason to create another copy of it in memory. A slideshow is a linear arrangement but frequently the user can jump around so it isn’t necessary to have things in linear order. You end up using the id names. If you have a large number of images, say your slideshow totals into the 100′s of megs, it may be better to load them on demand, not all at once.
[...] file that is loaded into your own SWF via the MovieClipLoader class to create the connection. …AS3 Tutorial: Creating a Slideshow: Page 2An Actionscript 3 (AS3) tutorial aimed at AS2 developers for creating a flash slideshow … all the [...]
[...] entries, it's WordPress-centric, since that's the blog system I use, but you can definitely applyAS3 Tutorial: Creating a SlideshowAn Actionscript 3 (AS3) tutorial aimed at AS2 developers for creating a flash slideshowHOW TO [...]