Apache Adobe Flex TutorialTutoriaux Adobe Flex & AIR en Français

26mar/092

Flex Item Renderer – Un itemRenderer optimisé en héritant de UIComponent

Héritez de la classe UICompenent est de loin la manière la plus optimale d'écrire un itemRenderer. Vous aurez le contrôle complet de votre code et le renderer sera aussi rapide que possible.

On va prendre l'exemple utilisé dans l'article sur l'optimisation des itemRenderer Flex pour le réécrire en se basant sur UIComponent. Cet itemRenderer fait simplement un changement de styles.

On crée donc une classe PriceItemRenderer.as qui va hériter d'UIComponent:

package renderers{
      import mx.controls.listClasses.IListItemRenderer;
      import mx.core.UIComponent;

      public class PriceItemRenderer extends UIComponent implements IListItemRenderer{
           public function PriceItemRenderer(){
                 super();
           }
      }
}

Vous avez du remarquer qu'en plus d'hériter d'UIComponent, on la fait implémenter l'interface IListItemRenderer. Il est nécessaire de le faire car un composant List va attendre des renderers qu'il implémentent cette interface. Si vous ne le faîtes pas, vous aurez une RTE (RunTime Error) car la liste tente de caster votre renderer en cette interface.

Si vous lisez la documentation sur IListItemRenderer, vous verrez que c'est un regroupement de nombreuses interfaces, dont la plupart sont déjà implémentéees par UIComponent.  Mais il y a une interface qu'UIComponent n'implémente pas: IDataRenderer. Il faut donc ajouter du code pour donner à votre classe la propriété "data" que vous allez tout du long.

Si vous  essayer d'utiliser cette classe sans implémenter IDataRenderer, vous obtiendrez cette erreur:

1044: Interface method get data in namespace mx.core:IDataRenderer not implemented by class renderers:PriceItemRenderer.

Modifier votre classe pour ajouter ce qui suit:

package renderers{
      import mx.controls.listClasses.IListItemRenderer;
      import mx.core.UIComponent;
      import mx.events.FlexEvent;

      public class PriceItemRenderer extends UIComponent implements IListItemRenderer{
           public function PriceItemRenderer(){
                 super();
           }

    // Internal variable for the property value.

    private var _data:Object;
    // Make the data property bindable.

    [Bindable("dataChange")]
    // Define the getter method.

    public function get data():Object {
        return _data;
    }
    // Define the setter method, and dispatch an event when the property

    // changes to support data binding.

    public function set data(value:Object):void {
        _data = value;
        dispatchEvent(new FlexEvent(FlexEvent.DATA_CHANGE));
    }
   }
}

Le code est pris directement depuis la documentation Flex sur IDataRenderer, vous n'avez même pas à la taper vous même. Maintenant que cela est fait, on peut ajouter nos deux Label:

  • Ajouter deux variables membre pour conserver les deux Label:
private var posLabel:Label; private var negLabel:Label;
  • Modifier la fonction set data() pour qu'elle appelle  invalidateProperties(). C'est important, car le changement de la data doit modifier le texte dans les Label et leur visibilité:
public function set data(value:Object):void {
	 _data = value;
	 invalidateProperties();
	 dispatchEvent(new FlexEvent(FlexEvent.DATA_CHANGE));
 }

Appelez  invalidateProperties() va indiquer au frameworkFlex qu'il doit appeler la fonction commitProperties au moment approprié et faire le rafraîchissement

  • Surchargez createChildren() et créez les labels, en les ajoutant à la liste d'affichage de votre composant. Notez qu'en plus de l'ajout/création des labels, leur styles et propriétés "visible" sont aussi assignées:
override protected function createChildren() : void        {
     super.createChildren();
     posLabel = new Label();
     posLabel.visible = false;
     posLabel.setStyle("color", 0x00FF00);
     addChild(posLabel);
     negLabel = new Label();
     negLabel.visible = false;
     negLabel.setStyle("color", 0xFF0000);
     addChild(negLabel);
}
  • Surchargez commitProperties() pour modifier les textes et la visibilité des Label. Vous pourriez aussi le faire dans set data() si cela vous arrange.
override protected function commitProperties():void           {
     super.commitProperties();
     posLabel.text = data.price;
     negLabel.text = data.price;
     posLabel.visible = Number(data.price) > 0;
     negLabel.visible = Number(data.price) < 0;
}
  • Surchargez updateDisplayList() pour dimensionner et positionner les labels. Vous devez les mettre à la bonne taille car de base elles sont de taille 0×0. C'est une chose qu'une classe Container ferait pour vous. Puisque c'est un itemRenderer simple, vous pouvez simplement fixer la taille des label à celle de l'itemRenderer:
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number ) : void{
     super.updateDisplayList(unscaledWidth, unscaledHeight);
     posLabel.move(0,0);
     posLabel.setActualSize(unscaledWidth,unscaledHeight);
     negLabel.move(0,0);
     negLabel.setActualSize(unscaledWidth, unscaledHeight);
}

Ce code peut sembler complexe à écrire mais rappeler vous que l'utilisation d'un Container ajouterait bien plus de code que cela.

Quelques informations supplémentaires sur UIComponent

La classe UIComponent est la classe de base pour tous les composants Flex (controles et conteneurs). Voici quelques tips d'utilisation:

  • UIComponent n'impose pas de restrictions de mise en page sur ses enfants (contrairement à un Container). Vous devrez dimensionner et positionner ces enfants vous-même.
  • Il est aussi possible d'afficher des graphics et de positionner des children au delà de la taille spécifiée dans  updateDisplayList().
  • Si vous souhaitez utiliser la propriété variableRowHeight d'une List, vous devez aussi surcharger measure() pour indiquer à la list la taille de l'itemRenderer.
  • Pour utiliser un UIComponent comme itemRenderer, vous devez implémenter IDataRenderer.
  • Pour utiliser la propriété  listData, vous devez implémenter IDropInListItemRenderer.

Articles similaires

Commentaires (2) Trackbacks (0)
  1. Bonjour,

    Je lutte depuis pas mal de temps, je n'arrive pas a modifier la largeur (columnWidth) pour chaque itemRenderer d'un HorizontalList. C'est pour afficher une list d'image et celles-ci n'ont pas la meme largeur.
    J'ai essayer d'overrider les functions qui peuvent régir la taille de mon item renderer, mais j'ai l'impression que de toute façon les classes parentes de l'HorizontalList la redéfinisse.

    Entre les drawTileBackgrounds(), drawItem(), commitProperties(), validateDisplayList()…. il semble qu'il y ait beaucoup de choses a modifier ; tout ce que j'ai pu faire n'a vraiment rien donné. Existe t'il une solution à votre connaissance ou des ressources a consulter qui pourraient m'aider.

    Merci beaucoup.

  2. Salut,
    si tu n'as pas trop d'éléments, tu peux essayer de le faire avec un Repeater sur une HBox qui vont contenir tes images. Ce sera un plus lent si tu as des dizaines et des dizaines d'éléments mais pour quelques uns, tu ne verras pas de différence.
    Sinon j'ai trouvé ça aussi:
    http://www.strawberrypixel.com/blog/flex-components/#hsmoothbox

    Poste ici ta solution si tu trouves :)
    Bonne Chance
    Fabien


Leave a comment

(required)

Aucun trackbacks pour l'instant