filterFunction et itemsChangedEffect
Depuis la beta 2 de Flex 3, il est possible d'appliquer des effets visuels sur les itemRenderer d'une List ou d'une TileList lorsque ces éléments sont ajoutés, déplacés ou supprimés de la collection à laquelle ils appartiennent.
Si vous ne voyez pas de quoi je parle, un exemple est présent sur ce blog : ICI
Il est possible que cet exemple vous fasse immédiatement penser au Flexstore d'Adobe: Lorsqu'on change la gamme de la marque ou que l'on spécifie une fourchette de prix, les éléments qui n'entrent pas dans ces catégories disparaissent avec un effet de 'Fade Out'. Si on regarde de plus près, cette application n'utilise pas d'itemChangeEffect, ce qui peut sembler normal puisque elle a été développé avec Flex 2 lors de sa sortie et que cette propriété n'existait pas encore.
Généralement, pour trier des objets d'une collection selon certains critères, on utilise la propriété filterFunction qu'implémente toutes les collections héritant de ICollectionView. Cette propriété attend une fonction qui définie quels sont les éléments que l'on souhaite garder dans la collection. Voici un simple exemple :
-
<mx:Script>
-
<![CDATA[
-
import mx.collections.ArrayCollection;
-
-
[Bindable]
-
private var coll:ArrayCollection = new ArrayCollection([
-
"Florian",
-
"Gui",
-
"Bruno",
-
"Gwenn",
-
"Michel",
-
"Magalie"]);
-
-
private function onComplete():void
-
{
-
coll.filterFunction = filterColl;
-
coll.refresh();
-
}
-
-
private function filterColl( data:String ):Boolean
-
{
-
var pattern:RegExp = new RegExp( inp_val.text, "i");
-
return ( data.search( pattern )> -1 );
-
}
-
]]>
-
</mx:Script>
-
<mx:TextInput id="inp_val" width="150" change="{coll.refresh()}" />
-
<mx:List id="lst_val" width="150" dataProvider="{coll}" />
A noter que lorsqu'on applique une fonction de filtre (ou de sort) sur une collection, il faut immédiatement faire appel à sa méthode refresh(). En effet, l'interface ICollectionView ne détecte pas les tris ou les filtres automatiquement, il faut donc faire appel à cette méthode obligatoirement après avoir défini une des ces 2 propriétés.
Maintenant que la méthode de filtre est implémentée , ajoutons voir les 2-3 lignes de code permettant de rajouter les effets sur les éléments :
-
<mx:List id="lst_val" width="150" dataProvider="{coll}" itemsChangeEffect="{myTileListEffect}"/>
-
<mx:DefaultTileListEffect id="myTileListEffect"
-
fadeOutDuration="500"
-
fadeInDuration="500"
-
/>
Testez l'application et vous remarquerez que ... rien ne se passe!
Il ne s'agit pas d'un bug mais d'un comportement assez normal finalement. Si l'on gratte un peu dans le code, on se rend compte que la classe ListCollectionView (la classe dont hérite ArrayCollection) possède une propriété de type Array , localIndex. Lorsqu'on ajoute une fonction de filtre à l'ArrayCollection, les éléments filtrés se retrouvent dans ce tableau et c'est à travers celui-ci qu'on accédera aux éléments par la suite. En analysant encore un peu plus le code, on trouve comment se déroule exactement le programme lorsqu'une fonction de filtre existe sur la collection :
1) On place tous les éléments de la collection dans localIndex
-
localIndex = list.toArray();
2) On parcourt les éléments du tableau. Chaque élément est 'traîté' dans la fonction filtre. Si la fonction filtre renvoi true, on place l'élément dans un tableau temportaire. Lorsque le parcours est terminé, on met à jour la propriété localIndex.
-
if (filterFunction != null)
-
{
-
var tmp:Array = [];
-
var len:int = localIndex.length;
-
for (var i:int = 0; i <len; i++)
-
{
-
var item:Object = localIndex[i];
-
if (filterFunction(item))
-
{
-
tmp.push(item);
-
}
-
}
-
localIndex = tmp;
-
}
Il s'agit d'un traitement assez classique mais il permet de savoir pourquoi les effets ne fonctionnent pas dans ce cas précis. En effet, on remarque qu'à chaque rafraichissement de la collection, le tableau est entièrement reconstruit. On ne sait donc jamais quels éléments ont été supprimés , ajoutés, déplacés entre chaque refresh. Ce sont ces informations qui sont nécessaires au itemChangeEffect pour pouvoir correctement se dérouler.
Pour contourner ce problème, une solution consiste à créer un tableau spécifique dans votre code qui enregistre les changements entre 2 refresh de la collection. Découpé en étapes, cela donne :
- Faire un refresh sur la collection de base
- Comparer la collection de base à la copie
- Mettre à jour la copie avec des ajouts ou de suppressions
- Création d'une copie de la collection de base.
- A chaque changement du filtre
Pour pouvoir comparer les éléments de chaque collection, il faudra s'assurer auparavant que les 2 collections soient triées de la même manière. Si vous changez de méthode de tri entre 2 mise à jour de filtres, n'oubliez donc pas de mettre à jour les 2 collections.
Dans l'exemple, j'ai comparé des chaînes de caractères mais on peut comparer n'importe quel autre objet du moment qu'on a implémenté la bonne méthode de comparaison.
Le résultat. La source est dispo en 'View Source'


4 mars 2008 a 4:04 pm
Merci Florian pour ce guide ultra-limpide !
Çà envoie du bois !