Forums Développement Multimédia

Les formations Mediabox
Les formations Mediabox

Créer un diaporama en ActionScript 3

Compatible ActionScript 3. Cliquer pour en savoir plus sur les compatibilités.Par tannoy (Antony Chauviré), le 09 juillet 2008
  • Révision : lilive - 16/05/2010

Le but de ce tuto est de créer un diaporama Flash en ActionScript 3 (AS3).

Caractéristiques du diaporama

  • Les chemins des images seront définis dans un fichier XML.
  • Les miniatures seront affichées en bas du document.
  • Un système de défilement horizontal sera mis en place pour les visualiser.
  • L’image sélectionnée sera affichée au dessus des miniatures.
Ce tutoriel vous expliquera une procédure à suivre pour mettre en place un tel diaporama. Il utilisera plusieurs notions d'ActionScript sans les détailler. Pour pouvoir suivre vous devrez être familiers des bases de la programmation en AS3. Des liens vous seront proposés dans certains passages, pour vous donner des pistes d'apprentissage si vous ne connaissez pas tel ou tel point.

Voici le diaporama qui va être réalisé:

L"extension Adobe Flash Plugin est nécessaire pour afficher ce contenu.



Le fichier XML des images

Afin de pouvoir modifier facilement les images du diaporama, nous allons les charger dynamiquement depuis un fichier XML.

Le fichier XML va contenir un nœud racine <images> et sera constitué de nœuds <image> possédant un attribut chemin.

<?xml version="1.0" encoding="utf-8"?>
<images>
	<image chemin="images/ptite-fleur.jpg"/>
	<image chemin="images/pluie.jpg"/>
	<image chemin="images/herbes.jpg"/>
	<image chemin="images/fleur-rouge.jpg"/>
	<image chemin="images/fleur-orange.jpg"/>
	<image chemin="images/eau.jpg"/>
	<image chemin="images/daffodils.jpg"/>
</images>



Les étapes de la réalisation du diaporama

Nous allons placer le code dans une classe ActionScript, que nous utiliserons en tant que classe du document.

Vous trouverez des informations sur la classe du document sur le wiki :
Où placer son code? La classe document dans Flash CS3

Nous allons successivement mettre en place les points suivants:

  • Mise en place de l’interface
  • Chargement du fichier XML contenant les chemins des images
  • Création des vignettes
  • Positionnement des vignettes
  • Défilement horizontal des vignettes
  • Affichage de l’image en taille normale



Mise en place de l’interface

Notre interface sera composée d’éléments dynamiques et de deux boutons présents dans la bibliothèque.

Voyez le .fla inclu dans les sources à télécharger, vous y trouverez 2 boutons dans la bibliothèque, respectivement associés aux classes NextButton et PreviousButton.
Vous pouvez aussi lire cette note.
Vous retrouverez toutes les explications pour utiliser ces éléments de la bibliothèque dans cette page du wiki : Pratique d'Actionscript 3 - Chapitre 5 - Les symboles

Notre interface va contenir les éléments suivants :

  • Un bouton précédent (classe PreviousButton auto-générée)
  • Un conteneur pour les vignettes
  • Un masque pour le conteneur des vignettes afin de ne visualiser que les vignettes qui seront entre les boutons.
  • Un conteneur pour les images en taille normale
  • 2 traits reliant les hauts et les bas des boutons

Nous allons donc définir ces différents éléments en tant qu’attributs privés de notre classe Diaporama.

 package {
	import NextButton;
	import PreviousButton;
 
	import flash.display.Shape;
	import flash.display.Sprite;
 
	public class Diaporama extends Sprite
	{		
		//Attributs
		private var nextButton:NextButton;
		private var previousButton:PreviousButton;
		private var conteneurVignettes:Sprite;
		private var masqueVignettes:Sprite;
		private var conteneurImages:Sprite;
		private var traitHaut:Shape;
		private var traitBas:Shape;
 
 
		public function Diaporama()
		{
 
		}
	}
}

Nous allons créer une méthode privée que nous appellerons addUI dans laquelle nous allons instancier les différents attributs.

		private function addUI():void
		{
			// Création des instances des éléments de l'interface ######################################
			nextButton = new NextButton();
			previousButton = new PreviousButton();
			conteneurVignettes = new Sprite();
			masqueVignettes = new Sprite();
			conteneurImages = new Sprite();
			traitHaut = new Shape();
			traitBas = new Shape();

Cette méthode va positionner les différents éléments de l’interface de cette façon :

  • Le bouton précédent sera à 5 pixels à gauche et en bas de la scène
  • Le bouton suivant sera à 5 pixels à droite et en bas de la scène
  • Les traits relieront les hauts et les bas des boutons
  • Le conteneur des vignettes et le masque des vignettes seront positionnés entre les boutons
  • Le conteneur des images sera centré horizontalement et à 10 pixels du haut de la scène

Pour tracer les traits, nous utiliserons la méthode statique distance() de la classe Point qui nous permet de récupérer la distance entre 2 points.

			// Positionnement et dessin ################################################################
 
			// Placements des boutons:
			nextButton.x = stage.stageWidth - (nextButton.width + 5);
			previousButton.x = 5;
			nextButton.y = previousButton.y = stage.stageHeight - (nextButton.height + 5);
 
			// Variable locale
			var distanceEntreBoutons:Number = Point.distance(
				new Point(previousButton.getBounds(this).right, previousButton.y),
				new Point(nextButton.x, previousButton.y)
			);
 
			// Dessin des traits en haut et en bas des vignettes:
			traitHaut.graphics.lineStyle(1, 0x333333);//epaisseur et couleur du trait
			traitHaut.graphics.moveTo(0, 0);//coordonnées de départ du trait
			traitHaut.graphics.lineTo(distanceEntreBoutons, 0);//coordonnées de fin du trait
			traitHaut.x = previousButton.getBounds(this).right;
			traitHaut.y = previousButton.y;
			traitBas.graphics.lineStyle(1, 0x333333);//epaisseur et couleur du trait
			traitBas.graphics.moveTo(0, 0);//coordonnées de départ du trait
			traitBas.graphics.lineTo(distanceEntreBoutons, 0);//coordonnées de fin du trait
			traitBas.x = traitHaut.x;
			traitBas.y = previousButton.getBounds(this).bottom - 1;
 
			// Dessin du masque (rectangle entre les 2 boutons):
			masqueVignettes.graphics.beginFill(0xFFFFFF);//couleur du masque
			// (elle n'a aucune importance puique l'objet va servir de masque)
			masqueVignettes.graphics.drawRect(0, 0, distanceEntreBoutons, previousButton.height);
 
			// Positionnements du conteneur et du masque
			conteneurVignettes.x = masqueVignettes.x = traitHaut.x;
			conteneurVignettes.y = masqueVignettes.y = traitHaut.y;

La propriété mask du conteneur des vignettes va être valorisée et prendra comme valeur l’objet de type Sprite masqueVignettes.

			// Masque du conteneur des vignettes #######################################################
			conteneurVignettes.mask = masqueVignettes;

Nous allons ensuite afficher les objets d’interface dans notre scène avec la méthode addChild().

			// Affichage de l'interface ################################################################
			addChild(nextButton);
			addChild(previousButton);
			addChild(conteneurVignettes);
			addChild(conteneurImages);
			addChild(traitHaut);
			addChild(traitBas);
		} 
		// Fin de la fonction addUI()

La méthode addUI() sera appelée lors de l'ajout du diaporama sur la scène. Cela nous permettra, comme on le verra plus tard, d'accéder à l'objet Stage, même quand le diaporama sera chargé dans un autre SWF.

Nous allons donc abonner notre diaporama à l'événement ADDED_TO_STAGE.

		public function Diaporama()
		{
			addEventListener(Event.ADDED_TO_STAGE, init);
		}
		private function init(e:Event):void
		{
		        addUI();//ajout de l'interface
		}



Chargement du fichier XML contenant le chemin des images

Le chargement d’un fichier XML va se faire grâce à la classe URLLoader.

Je vous invite à relire cet article pour bien comprendre le principe de chargement.

Nous allons ajouter une méthode privée nommée loadImagesPath() qui va se charger de lancer le chargement du fichier XML , de définir le gestionnaire d’événements qui va traiter la fin du chargement et de définir le gestionnaire d’événements qui va traiter les erreurs.

		private function loadImagesPath():void
		{
			var urlLoader:URLLoader = new URLLoader(); //conteneur de chargement du fichier XML
			urlLoader.addEventListener(Event.COMPLETE, loadImagesPathCompleted); //abonnement à l'événement Event.COMPLETE
			urlLoader.addEventListener(IOErrorEvent.IO_ERROR, loadImagesPathIoError); //abonnement à l'événement IOErrorEvent.IO_ERROR
			urlLoader.load(new URLRequest("xml/diaporama.xml")); //chargement du fichier XML
		}

La méthode loadImagesPath sera appelée dans la fonction de rappel de l'événement ADDED_TO_STAGE, juste après la méthode qui crée l’interface.

		private function init(e:Event):void
		{
		        addUI();//ajout de l'interface
		        loadImagesPath();//chargement des chemins des images
		}

Le gestionnaire d’événements loadImagesPathIoError sera invoqué lorsqu’une erreur de chargement aura lieu. Un rectangle occupant la taille de la scène sera créé et un message d’erreur sera affiché.

		private function loadImagesPathIoError(evt:IOErrorEvent):void
		{
			//Rectangle de couleur noir couvrant la totalité de la scène
			var cache:Shape = new Shape();
			cache.graphics.beginFill(0x000000);
			cache.graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
			addChild(cache);
			//Message d'erreur
			var message:TextField = new TextField();
			message.autoSize = TextFieldAutoSize.LEFT;
			message.defaultTextFormat = new TextFormat("Verdana", 28);
			message.text = "Une erreur de chargement a eu lieu !";
			message.textColor = 0xFFFFFF;
			message.x = (stage.stageWidth - message.textWidth) / 2;
			message.y = (stage.stageHeight - message.textHeight) / 2;
			addChild(message);
		}



Création des vignettes

Le gestionnaire d’événements loadImagesPathCompleted sera invoqué à la fin du chargement du fichier XML.

Un message indiquant le chargement en cours des images sera affiché dans le conteneur des vignettes. Cet objet de type TextField sera un attribut privé de notre classe.

Nous allons donc récupérer notre structure XML et la parcourir dans sa globalité avec une boucle for each.

A chaque passage de la boucle, nous allons créer un objet de type Loader, qui nous permettra de charger les images.

Je vous invite à relire si vous le souhaitez l’article sur le chargement des images : Charger des images ou des swf en ActionScript 3 (AS3)

L’objet Loader via sa propriété contentLoaderInfo s’abonnera à l’événement Event.COMPLETE afin d’afficher les images, une fois chargées, dans le conteneur des vignettes.

 private function loadImagesPathCompleted(evt:Event):void
		{
			//Message de chargement
			messageChargement  = new TextField();
			messageChargement.autoSize = TextFieldAutoSize.LEFT; //redimensionnement automatique à partir de la gauche
			messageChargement.selectable = false; //Le texte n'est pas sélectionnable
			messageChargement.text = "Chargement en cours..."; //Message indiquant un chargement en cours
			messageChargement.x = (traitHaut.width - message.textWidth) / 2; // position x du message dans le conteneur
			messageChargement.y = (nextButton.height - message.textHeight) / 2; // position y du message dans le conteneur
			conteneurVignettes.addChild(messageChargement); // le message est ajouté dans le conteneur des vignettes
 
			// Flux XML
			var xml:XML = new XML(evt.target.data); //Récupération du flux XML
			var xmlList:XMLList = xml.elements(); //Récupération de la liste des noeuds image
			for each(var image:XML in xmlList)
			{
				var loader:Loader = new Loader(); //conteneur pour chaque image
				loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadImageCompleted); //abonnement à l'événement Event.COMPLETE
				loader.load(new URLRequest(image.@chemin)); //chargement de l'image
			}
		} 

Le gestionnaire d’événements loadImageCompleted sera invoqué à la fin du chargement d’une image.

Le message de chargement sera supprimé de l’interface s’il est présent dans le conteneurVignettes. On utilisera pour cela la méthode contains() de la classe DisplayObjectContainer.

Afin de gérer le positionnement des vignettes (que l’on évoquera par la suite), nous allons abonner le conteneur des vignettes à l’événement Event.added. Cet événement est évoqué lorsqu’un objet d’affichage est ajouté à une liste d’affichage.

L’image sera redimensionnée proportionnellement en fonction de la hauteur du conteneurVignettes puis elle sera ajoutée à ce conteneur.

 private function loadImageCompleted(evt:Event):void
		{
			if (conteneurVignettes.contains(messageChargement)) //si le conteneur de vignettes contient le message de chargement
			{
				conteneurVignettes.removeChild(messageChargement); //alors il est supprimé de l'interface
			}
 
			conteneurVignettes.addEventListener(Event.ADDED, imageAdded); //abonnement du conteneur des vignettes à l'événement Event.ADDED
 
			var loader:Loader = evt.target.loader; //conteneur de l'image
			var ratio:Number = loader.height / nextButton.height; //ratio pour le redimensionnement des images
			loader.width /= ratio; //largeur de la vignette
			loader.height /= ratio; //hauteur de la vignette
			conteneurVignettes.addChild(loader); //ajout de la vignette dans le conteneur
		} 



Positionnement des vignettes

Afin de gérer facilement le positionnement des vignettes, nous allons utiliser l’événement Event.ADDED. Cet événement sera évoqué lorsqu’une vignette sera ajoutée dans le conteneur.

Lors de l’ajout d’une vignette, nous récupèrerons la coordonnée x de la vignette précédemment ajoutée et nous repositionnerons notre vignette en fonction de cette coordonnée et d’une constante définissant l’écart entre les vignettes.

Nous utiliserons pour cela les méthodes de gestion d’une liste d’affichage. Je vous invite pour cela à lire l’article du wiki à ce sujet : La nouvelle architecture du framework AS3

Les vignettes seront ensuite abonnées à l’événement MouseEvent .CLICK afin d’afficher l’image à sa taille réelle.

 private function imageAdded(evt:Event):void
		{
			var loader:Loader = evt.target as Loader; //la vignette qui est ajoutée
			var conteneur:Sprite = evt.currentTarget as Sprite; //le conteneur des vignettes
			var index:int = conteneur.getChildIndex(loader); //l'index dans la liste d'affichage
			if(index != 0) //si la vignette n'est pas la première
			{
				var previousX:Number = conteneur.getChildAt(index - 1).getBounds(conteneur).right; //coordonnée X du côtét droit de la vignette précédemment ajoutée
				loader.x = previousX + ECART_VIGNETTES; //positionnement de la vignette 10 pixels après la vignette précédente
			}
			loader.addEventListener(MouseEvent.CLICK, vignetteClic); //abonnement à l'événement clic
		}

A ce stade, nous remarquons qu’il nous est impossible de visualiser toutes les vignettes. Nous allons donc mettre en place un système de défilement horizontal.



Défilement horizontal des vignettes

Le défilement des vignettes va se faire lors du survol des boutons nextButton et previousButton. Le bouton next diminuera la position x du conteneur des vignettes et le bouton previous augmentera cette position x.

Nous devons donc abonner les boutons aux évènements MouseEvent.MOUSE_OVER et MouseEvent.MOUSE_OUT pour les rendre réactifs au passage de la souris, et leur permettre de controler le défilement des vignettes. Nous allons ajouter ces abonnements à la fin de la méthode addUI():

		private function addUI():void
		{
			// ...... le début de la méthode n'a pas changé ......
			// Affichage de l'interface ################################################################
			addChild(nextButton);
			addChild(previousButton);
			addChild(conteneurVignettes);
			addChild(conteneurImages);
			addChild(traitHaut);
			addChild(traitBas);
 
 
			// Rendre les boutons de défilement réactifs ################################################
			nextButton.addEventListener(MouseEvent.MOUSE_OVER, scrollNextButtonOver); //abonnement à l'événement MouseEvent.MOUSE_OVER
			nextButton.addEventListener(MouseEvent.MOUSE_OUT, scrollNextButtonOut); //abonnement à l'événement MouseEvent.MOUSE_OUT
			previousButton.addEventListener(MouseEvent.MOUSE_OVER, scrollPreviousButtonOver); //abonnement à l'événement MouseEvent.MOUSE_OVER
			previousButton.addEventListener(MouseEvent.MOUSE_OUT, scrollPreviousButtonOut); //abonnement à l'événement MouseEvent.MOUSE_OUT
		}
		// Fin de la fonction addUI()

Pour gérer le défilement, nous allons utiliser un objet de type Timer. Cet objet permet d’exécuter des actions à intervalle régulier. Dans notre cas, il fera défiler à intervalle régulier le conteneur des vignettes. Cet objet Timer sera définir en tant qu’attribut et sera instancié dans la méthode addUI.

		//Attributs
		private var nextButton:NextButton;
		private var previousButton:PreviousButton;
		private var conteneurVignettes:Sprite;
		private var masqueVignettes:Sprite;
		private var conteneurImages:Sprite;
		private var traitHaut:Shape;
		private var traitBas:Shape;
		private var messageChargement:TextField
		private const ECART_VIGNETTES:int = 10;
		private var timer:Timer;

Le constructeur de la classe Timer prend en paramètre le délai d’exécution entre chaque appel. Ce délai est exprimé en millisecondes.

		private function addUI():void
		{
			//Instances
			nextButton = new NextButton();
			previousButton = new PreviousButton();
			conteneurVignettes = new Sprite();
			masqueVignettes = new Sprite();
			conteneurImages = new Sprite();
			traitHaut = new Shape();
			traitBas = new Shape();
			timer = new Timer(50); // Création du Timer

Les gestionnaires d’événements scrollNextButtonOver et scrollPreviousButtonOver seront invoqués lorsque l’utilisateur survolera le bouton nextButton et le bouton previousButton avec le curseur de la souris.

Ils abonneront un objet Timer, un objet de gestion du temps, à l’événement TimerEvent.TIMER. Cet événement sera invoqué à intervalle régulier, défini dans le constructeur de l’objet timer.

Le timer sera lancé avec la méthode start().

		private function scrollNextButtonOver(evt:MouseEvent):void
		{
			timer.addEventListener(TimerEvent.TIMER, scrollNextTimer); //abonnement à l'événement TimerEvent.TIMER
			timer.start(); //démarrage du timer
		}
 
		private function scrollPreviousButtonOver(evt:MouseEvent):void
		{
			timer.addEventListener(TimerEvent.TIMER, scrollPreviousTimer); //abonnement à l'événement TimerEvent.TIMER
			timer.start(); //démarrage du timer
		}

Les gestionnaires d’événements scrollNextButtonOut et scrollPreviousButtonOut seront invoqués lorsque l’utilisateur sortira du survol du bouton nextButton et du bouton previousButton.

Ils annuleront l’abonnement à l’événement TimerEvent.TIMER.

		private function scrollNextButtonOut(evt:MouseEvent):void
		{
			timer.removeEventListener(TimerEvent.TIMER, scrollNextTimer); //annulation de l'abonnement à l'événement TimerEvent.TIMER
		}
 
		private function scrollPreviousButtonOut(evt:MouseEvent):void
		{
			timer.removeEventListener(TimerEvent.TIMER, scrollPreviousTimer); //annulation de l'abonnement à l'événement TimerEvent.TIMER
		}

Le gestionnaire d’événements scrollNextTimer est invoqué lorsque l’utilisateur survole le bouton nextButton. Ce gestionnaire est appelé à intervalles réguliers.

Il a pour but de déplacer le conteneur de vignettes afin de visualiser les vignettes masquées. Le déplacement se fera vers la gauche, il nous faudra donc diminuer la coordonnée x du conteneur.

Cette diminution se fera en fonction d’une constante nommée PAS_DEPLACEMENT et définie en tant qu’attribut de la classe.

		//Attributs
		private var nextButton:NextButton;
		private var previousButton:PreviousButton;
		private var conteneurVignettes:Sprite;
		private var masqueVignettes:Sprite;
		private var conteneurImages:Sprite;
		private var traitHaut:Shape;
		private var traitBas:Shape;
		private var messageChargement:TextField;
		private const ECART_VIGNETTES:int = 10;
		private var timer:Timer;
		private const PAS_DEPLACEMENT:int = 10;

A chaque appel du gestionnaire d’événements, le conteneur des vignettes sera déplacé de la valeur de la constante PAS_DEPLACEMENT vers la gauche.

Un test sera effectué afin de ne pas déplacer le bord droit du conteneur au delà du bord droit du masque.

		private function scrollNextTimer(evt:TimerEvent):void
		{
			if (conteneurVignettes.getBounds(this).right >= (masqueVignettes.getBounds(this).right + PAS_DEPLACEMENT))//si le bord droit du conteneur est positionné après le bord droit du masque
			{
				conteneurVignettes.x -= PAS_DEPLACEMENT; // le conteneur est déplacé vers la gauche
			}
			else
			{
				timer.removeEventListener(TimerEvent.TIMER, scrollNextTimer); //annulation de l'abonnement à l'événement TimerEvent.TIMER
			}
		}

Le gestionnaire d’événements scrollPreviousTimer, lui, est invoqué lorsque l’utilisateur survole le bouton previousButton. Ce gestionnaire est appelé à intervalles réguliers. Son fonctionnement est très semblable au précédent, à ceci près que le déplacement se fera vers la droite, en augmentant la coordonnée x du conteneur, et qu'il faut faire le test pour ne pas déplacer le bord gauche du conteneur au delà du bord gauche du masque.

		private function scrollPreviousTimer(evt:TimerEvent):void
		{
			if (conteneurVignettes.x <= (masqueVignettes.x - PAS_DEPLACEMENT))//si le bord gauche du conteneur est positionné avant le bord gauche du masque
			{
				conteneurVignettes.x += PAS_DEPLACEMENT; // le conteneur est déplacé vers la droite
			}
			else
			{
				timer.removeEventListener(TimerEvent.TIMER, scrollPreviousTimer); //annulation de l'abonnement à l'événement TimerEvent.TIMER
			}
		}



Affichage de l’image en taille normale

L’image étant déjà chargée dans notre diaporama, nous n’allons pas la recharger une seconde fois dans sa taille initiale. Nous allons utiliser les classes du framework ActionScript 3 qui permettent de manipuler les images. Ces classes sont les classes Bitmap et BitmapData.

Dans le gestionnaire d’événements vignetteClic, qui est invoqué lors du clic sur une vignette, nous allons récupérer l’image grâce à la propriété contentLoaderInfo de l’objet Loader.

En effet, l’objet LoaderInfo est un objet qui est partagé entre le conteneur et l’image chargée. Cet objet contient une propriété content qui nous permet de récupérer l’image.

		private function vignetteClic(evt:MouseEvent):void
		{
			// image correspondant à la vignette cliquée
			var image:Bitmap = (evt.currentTarget as Loader).contentLoaderInfo.content as Bitmap;

Puis nous allons appeler une fonction nommée afficheImage qui fera le travail d'afficher l'image cliquée en grand:

			// afficher cette image
			afficheImage(image);
		}
		// Fin de la méthode vignetteClic

Créons la fonction afficheImage, qui attend comme paramètre l'image à afficher en grand:

		private function afficheImage(image:Bitmap):void
		{

Nous allons commencer par récupérer les pixels de l’image grâce à la propriété bitmapData de la classe Bitmap.

			var pixels:BitmapData = image.bitmapData; // pixels de l'image

Ces pixels vont ensuite être copiés dans un autre objet BitmapData grâce à la méthode copyPixels() . Le constructeur de la classe BitmapData attend en paramètres la largeur et la hauteur de la zone de pixels.

			var newPixels:BitmapData = new BitmapData(pixels.width, pixels.height); //conteneur de la copie des pixels
			newPixels.copyPixels(pixels); //copie des pixels

Un objet BitmapData n’étant pas un objet d’affichage, nous allons instancier un objet Bitmap en lui passant en paramètres les pixels copiés. L’objet Bitmap pourra ensuite être ajouté au conteneur des images.

			var newImage:Bitmap = new Bitmap(newPixels); //Image en taille réelle

Avant d'ajouter cet objet au conteneur des images, nous allons d'abord en enlever l'image précédemment affichée (si elle existe), et détruire les pixels de cette image, pour libérer la mémoire au fur et à mesure:

			if (conteneurImages.numChildren != 0) //si le conteneur contient déjà une image
			{
				var oldImage:Bitmap = conteneurImages.getChildAt(0) as Bitmap; // on récupère l'image affichée
				conteneurImages.removeChild(oldImage);// l'image est supprimée de la liste d'affichage
				oldImage.bitmapData.dispose(); // on libère la mémoire occupée par cette image
			}

Nous pouvons maintenant ajouter la nouvelle image, ce qui achève notre méthode afficheImage:

			conteneurImages.addChild(newImage);
			conteneurImages.x = (stage.stageWidth - conteneurImages.width) / 2;
			conteneurImages.y = 10;
		}
		// Fin de la méthode afficheImage.

A ce stade le diaporama est déjà fonctionnel. Nous allons simplement faire en sorte qu'une première image s'affiche en grand au moment où la première achève son chargement:

		private function loadImageCompleted(evt:Event):void
		{
			var loader:Loader = evt.target.loader; //conteneur de l'image
 
			if (conteneurVignettes.contains(messageChargement)) //si le conteneur de vignettes contient le message de chargement
			{
				conteneurVignettes.removeChild(messageChargement); //alors il est supprimé de l'interface
				// et on affiche la première image chargée:
				var image:Bitmap = loader.contentLoaderInfo.content as Bitmap;
				afficheImage(image);
 
			}
 
			conteneurVignettes.addEventListener(Event.ADDED, imageAdded); //abonnement du conteneur des vignettes à l'événement Event.ADDED
 
			var ratio:Number = loader.height / nextButton.height; //ratio pour le redimensionnement des images
			loader.width /= ratio; //largeur de la vignette
			loader.height /= ratio; // hauteur de la vignette
			conteneurVignettes.addChild(loader); //ajout de la vignette dans le conteneur
		}

Conclusion

Nous venons donc de créer un diaporama dynamique. Il ne vous reste plus qu’à apporter vos améliorations afin de le faire correspondre au maximum à vos besoins. Vous pouvez même faire profiter les autres de vos améliorations en éditant cette page et en ajoutant votre contribution au paragraphe Variantes ci-dessous.

Vous pouvez poser des questions ou faire des remarques au sujet de ce tutoriel ici.

Sources

Téléchargez ici les sources au format CS3.



Variantes

Charger les images dans l'ordre

Par lilive, le 16/05/2010.

Voici une variante du diaporama où on fait attention à charger les images dans l'ordre où elles sont listées dans le XML.

Le diaporama de base se contente de parcourir les noeuds du XML et de lancer aussitôt le chargement de chacune des images. Tous les chargements démarrent alors de manière quasi-simultanée. Les premières vignettes à s'afficher seront donc celles des premières images qui auront fini de se charger, et il n'est pas possible de choisir l'ordre dans lequel on veut les ranger.

Cette variante charge les images les unes après les autres, en respectant leur ordre d'apparition dans le fichier XML, et attend qu'une image ait fini de se charger pour lancer le chargement de l'image suivante.

Pour cela nous allons utiliser un tableau nommé imagesToLoad qui stockera les URLs des images à charger. Commençons par déclarer ce tableau:

		//Attributs
		private var nextButton:NextButton;
		private var previousButton:PreviousButton;
		private var conteneurVignettes:Sprite;
		private var masqueVignettes:Sprite;
		private var conteneurImages:Sprite;
		private var traitHaut:Shape;
		private var traitBas:Shape;
		private var messageChargement:TextField;
		private const ECART_VIGNETTES:int = 10;
		private var timer:Timer;
		private const PAS_DEPLACEMENT:int = 8;
		private var imagesToLoad:Array; // Tableau pour la liste des URLs à charger

Maintenant remplissons ce tableau en parcourant le fichier XML, dans la méthode loadImagesPathCompleted.

		private function loadImagesPathCompleted(evt:Event):void
		{
			//Message de chargement
			messageChargement  = new TextField();
			messageChargement.autoSize = TextFieldAutoSize.LEFT; //redimensionnement automatique à partir de la gauche
			messageChargement.selectable = false; //Le texte n'est pas sélectionnable
			messageChargement.text = "Chargement en cours..."; //Message indiquant un chargement en cours
			messageChargement.x = (traitHaut.width - messageChargement.textWidth) / 2; // position x du message dans le conteneur
			messageChargement.y = (nextButton.height - messageChargement.textHeight) / 2; // position y du message dans le conteneur
			conteneurVignettes.addChild(messageChargement); // le message est ajouté dans le conteneur des vignettes
 
			// Extraction d'un tableau d'urls à partir du XML
			imagesToLoad = new Array(); // Initialisation du tableau
			var xml:XML = new XML(evt.target.data); //Récupération du flux XML
			var xmlList:XMLList = xml.elements(); //Récupération de la liste des noeuds image
			for each(var image:XML in xmlList)
				imagesToLoad.push(image.@chemin); // Ajout des URLs au tableau

Une fois le tableau imagesToLoad rempli, appelons une fonction qui va se charger de lancer le chargement de la première image contenue dans le tableau:

			loadNextImage();
		}
		// Fin de la méthode loadImagesPathCompleted

Cette fonction loadNextImage va donc regarder s'il y a encore une URL disponible dans le tableau, et lancer le chargement de cette URL tout en l'otant du tableau. Ainsi le tableau va diminuer petit à petit, jusqu'à être vide. Pour récupérer le premier élément du tableau tout en l'enlevant du tableau, nous utilisons la méthode shift de la classe Array:

		private function loadNextImage():void
		{
			if (imagesToLoad.length == 0) return; // Si le tableau est vide, ne rien faire
 
			var loader:Loader = new Loader(); //conteneur pour la prochaine image à charger
			loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadImageCompleted); //abonnement à l'événement Event.COMPLETE
			loader.load(new URLRequest(imagesToLoad.shift())); //chargement de la première image du tableau, en même temps qu'on l'enlève du tableau
		}

Il nous reste à modifier la méthode loadImageCompleted pour qu'à la fin du chargement d'une image, le chargement de l'image suivante du tableau soit lancé. Il nous suffit de rajouter une ligne à la fin de la fonction:

		private function loadImageCompleted(evt:Event):void
		{
			var loader:Loader = evt.target.loader; //conteneur de l'image
 
			if (conteneurVignettes.contains(messageChargement)) //si le conteneur de vignettes contient le message de chargement
			{
				conteneurVignettes.removeChild(messageChargement); //alors il est supprimé de l'interface
				// et on affiche la première image chargée:
				var image:Bitmap = loader.contentLoaderInfo.content as Bitmap;
				afficheImage(image);
 
			}
 
			conteneurVignettes.addEventListener(Event.ADDED, imageAdded); //abonnement du conteneur des vignettes à l'événement Event.ADDED
 
			var ratio:Number = loader.height / nextButton.height; //ratio pour le redimensionnement des images
			loader.width /= ratio; //largeur de la vignette
			loader.height /= ratio; // hauteur de la vignette
			conteneurVignettes.addChild(loader); //ajout de la vignette dans le conteneur
 
			loadNextImage(); // Charge la prochaine image (s'il en reste)
		}

Et voilà, le diaporama charge maintenant les images une à une, dans l'ordre que nous choisissons.

Téléchargez ici les sources au format CS3.