Forums Développement Multimédia

Les formations Mediabox
Les formations Mediabox



Personnaliser le composant TabNavigator

Compatible Flex 2. Cliquer pour en savoir plus sur les compatibilités.Compatible ActionScript 3. Cliquer pour en savoir plus sur les compatibilités.Par ITERATIF (Olivier Bugalotto), le 24 février 2007

Continuons sur la lancée du précédent article, pour créer un composant Tabs héritant du composant TabNavigator en ajoutant un bouton de fermeture à chaque onglet. Voici un apercu du composant Tab :

Correction

Dans un premier temps nous allons effectuer quelques corrections au niveau du composant TabCloser (voir : Le composant TabControl). Voici le defaut que nous devons corriger:

Pour rémedier à ce probleme, nous allons faire en sorte que le composant TabCloser prenne en compte les dimensions du bouton de fermeture. Pour faire cela, nous allons simplement redimensionner la taille de l'étiquette de manière a ce qu'elle prenne en compte la taille du bouton de fermeture et nous le ferons dans la méthode layoutContents :

package net.iteratif.controls
{
	...
 
	use namespace mx_internal;
 
	public class TabCloser extends Tab
	{
		....
 
		mx_internal override function layoutContents(unscaledWidth:Number,
                                        unscaledHeight:Number,
                                        offset:Boolean):void {
                        super.layoutContents(unscaledWidth,unscaledHeight,offset);
 
			var viewWidth:Number = unscaledWidth;
 
			// Obtient l'espacement entre 2 composants
			var horizontalGap:Number = getStyle("horizontalGap");
			// Obtient l'espace a gauche
			var paddingLeft:Number = getStyle("paddingLeft");
			// Obtient l'espace à droite
			var paddingRight:Number = getStyle("paddingRight");
 
			// Nous verifions si une icone est presente.
			// Si c'est la cas nous recuperons sa largeur.
			var iconWidth:Number = 0;
			if(currentIcon)
				iconWidth = currentIcon.width;
 
			// Nous redimensionnons la largeur de l'etiquette du bouton
			// en prenant en compte celle du bouton de fermeture.
			textField.width = viewWidth - iconWidth - closeButton.width - horizontalGap -
                                                   paddingLeft - paddingRight;
 
			closeButton.x = viewWidth - closeButton.width - paddingRight;
                        // Nous positionnons le bouton de fermeture a la
                        // meme hauteur que le libelle.
                        closeButton.y = textField.y;
 
			setChildIndex(closeButton, numChildren - 1);
		}
                ...
}

Nous allons aussi ajouter un style au bouton de fermeture en définissant une feuille de styles que nous passerons en paramètre du compilateur :

-theme CloseButtonSyle.css

La feuille de style CloseButtonStyle :

/* Style du Bouton de fermeture */
.closeButton {
	upSkin: Embed(source="upClose.png");	
	overSkin: Embed(source="downClose.png");
	downSkin: Embed(source="downClose.png");
}

Voici le rendu aprés correction :

Création du composant Tabs

Passons maintenant à la création du composant Tabs. Premiere chose, une nouvelle classe Tabs héritant de TabNavigator :

package net.iteratif.controls
{
	import mx.containers.TabNavigator;
 
	public class Tabs extends TabNavigator
	{
		public function Tabs() {
			super();
		}
	}
}

Aprés une rapide étude du composant TabNavigator, nous constatons que ce dernier instancie et nous l'aurions deviné, un composant TabBar. Il nous suffit donc de remplacer celui-ci par une instance de TabControl et nous le ferons en redéfinissant la méthode createChildren :

package net.iteratif.controls
{
	import mx.containers.TabNavigator;
 
	public class Tabs extends TabNavigator
	{
		public function Tabs() {
			super();
		}
 
		protected override function createChildren():void {
			super.createChildren();
 
			// Verifie que le composant TabBar est instancie
			// pour le retirer et le remplacer par notre
			//composant TabControl.
			if(tabBar) {
				rawChildren.removeChild(tabBar);
 
				tabBar = new TabControl();
				tabBar.name = "tabBar";
	                        tabBar.focusEnabled = false;
                                // Nous appliquons le style du composant au notre
	                        tabBar.styleName = this;
 
                                // Nous modifions certains style
	                        tabBar.setStyle("borderStyle", "none");
	                        tabBar.setStyle("paddingTop", 0);
	                        tabBar.setStyle("paddingBottom", 0);
 
                                // Nous ajoutons le notre composant
	                        rawChildren.addChild(tabBar);
			}
		}
	}
}

remarque: La propriété rawChildren est une propriété de la classe container. Elle stocke uniquement les composants énumérables, ce qui évite d'énumérer les parties correspondantes à l'apparence du conteneur.

Gérer la suppression d'un onglet

Notre composant TabControl emet un évènement ITEM_CLOSE indiquant la demande de suppression d'un onglet, il nous suffit alors simplement d'écouter cet évènement par notre composant Tabs pour supprimer l'onglet sélectionné :

package net.iteratif.controls
{
	import mx.containers.TabNavigator;
 
        // evenement personnalise
	import net.iteratif.events.ItemCloseEvent;
 
	public class Tabs extends TabNavigator
	{
		...
 
		protected override function createChildren():void {
			super.createChildren();
 
			if(tabBar) {
				...
				// Nous ecoutons l'evenement emit par TabControl
				// lorsqu'une demande de suppression est demandee.
				tabBar.addEventListener(ItemCloseEvent.ITEM_CLOSE,destroyItem);
	                        ...
			}
		}
 
		protected function destroyItem(e:ItemCloseEvent):void {
			// Nous retirons le conteneur correspondant
			// a son index.
			removeChildAt(e.index);
		}
	}
}

Il est important avant d'étendre un composant de bien l'étudier … ;)

Code source du composant Tabs : http://www.iteratif.fr/flex2/tabs/Tabs.zip

Par ITERATIF - BUGALOTTO Olivier (2007) Vous pouvez retrouver ce tutorial et des commentaires à ce sujet sur mon blog