Pour un nouveau composant Flex que je développe, j'avais besoin de savoir quand l'utilisateur était en train de se servir de l'application ou s'il avait switché sur un autre onglet ou une autre fenêtre. En effet, ce composant va afficher un élément graphique à l'écran pendant un certain temps (quelques secondes) et si l'utilisateur n'a pas le focus sur l'application Adobe Flex, il pourrait ne jamais voir cet élément apparaître.
Adobe Flash Player et Adobe AIR proposent pour cela des évènements indiquant la perte ou la reprise du focus sur l'application. Ces évènements sont de type Event.ACTIVATE et Event.DEACTIVATE. Cet évènement est un évènement broadcast, ce qui signifie qu'il est dispatché par tous les objets de type EventDispatcher (ou qui en héritent). Cela signifie donc que tous les composants visuels dispatchent cet évènement car ils héritent de EventDispatcher.
Vous pouvez donc vous abonner directement à l'évènement depuis votre composant graphique avec:
addEventListener(Event.ACTIVATE, onActivate);
addEventListener(Event.DEACTIVATE, onDeactivate);
Application de démonstration
Voici une petite application Adobe Flex pour montrer ce comportement. Quand vous allez changer de fenêtre ou d'onglet, cet application va tracer la perte / reprise du focus.
Notez que l'application n'aura pas le focus à la création tant que vous n'aurez pas cliqué dessus!
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="onCreationComplete()">
<mx:Script>
<![CDATA[
private function onCreationComplete():void {
addEventListener(Event.ACTIVATE, onActivate);
addEventListener(Event.DEACTIVATE, onDeactivate);
}
private function onActivate(event:Event):void {
monitor.text += "onActivate::" + event.toString() + "\r";
}
private function onDeactivate(event:Event):void {
monitor.text += "onDeactivate::" + event.toString() + "\r";
}
]]>
</mx:Script>
<mx:Panel title="Event Monitor">
<mx:TextArea id="monitor" width="550" height="300"/>
</mx:Panel>
</mx:Application>
Flex Source Code Download: Télécharger le code source complet de l'application
This movie requires Flash Player 11
Un peu de retard sur cette news mais elle reste importante. Le projet anciennement Adobe Cocomo qui est devenu Adobe Flash Collaboration Service (AFCS) devient maintenant LiveCycle Collaboration Service (LCCS). Ce nom serait à priori le nom définitif.
Il faut noter que LCCS ne vous oblige pas à acheter LCDS (LiveCycle Data Service), c'est simplement le nom qui change.
Pour ceux qui ne connaissent pas le produit de base, LCCS permet d'offrir des services "in the cloud", c'est-à-dire d'utiliser l'architecture d'Adobe (serveurs) pour le fonctionnement de votre application. LCCS se compose d'un SDK comprenant un ensemble de composants personnalisables pour ce qui concerne les activités collaboratives et temps réel:
- Communication Audio VoIP
- Communication Vidéo WebCam
- Chat
- Tableau Blanc Multi-utilisateur (avec ses outils de dessin etc.)
- Partage de fichiers temps réel
- Gestion des utilisateurs (accès et droits)
Plus d'informations sur LCCS (anciennement Cocomo)
Un service toujours gratuit mais limité en accès pour les développeurs
Dans la partie suivante, je donne les prix de l'accès au service. Pour les développeurs qui ne veulent pas payer pour tester LCCS, Adobe accorde un solde gratuit de 15$ à utiliser par les conditions suivantes.
Après le Metatag DefaultProperty, très utile pour les composants instanciés en MXML, voici une autre astuce que vous devez absolument connaître si vous développez des composants Flex personnalisés. Ce metatag permet d'indiquer au compilateur que votre classe va propager (dispatch) un évènement. Ce n'est pas une étape obligatoire, si vous faîtes un dispatchEvent() dans votre composant, votre évènement sera toujours propagé.
Le principal avantage qu'il apport est un confort de développement, puisque Flex Builder va faire de l'auto-complétion sur votre code (en MXML et en AS). Vous avez donc moins de chances de vous trompez et vous pouvez ainsi réaliser une vraie API.
Ajouter le Metatag Event à sa classe
Notez que pour pouvoir dispatcher un Event depuis votre classe / composant, votre classe doit hériter de EventDispatcher (ou passer par un objet qui en hérite). Vous aurez ainsi accès aux méthodes dispatchEvent() et addEventListener(). Pour ce métatag, 2 attributs sont à préciser au minimum:
- name: Le type d'Event (sous forme de String) ainsi que le type d'objet évènement.
- type: Le type d'objet évènement, il faut donner le "qualified name" de la classe, c'est à dire le nom de la classe avec les noms de packages. Si vous propagez un simple event,il faut par exemple donner: flash.event.Event.
Pour une classe ActionScript
Dans le cas d'une classe ActionScript, il suffit de placer le Metatag juste avant la déclaration de classe:
package comp {
import flash.events.Event;
import flash.events.EventDispatcher;
[Event(name="enableChanged", type="myeventpackage.CustomEvent")]
public class MonComposant extends EventDispatcher {
private var _enabled:Boolean=false;
public function MonComposant() {
}
public function set enabled(value:Boolean):void {
dispatchEvent(new CustomEvent("enableChanged"));
}
}
}
// fichier event custom
package myeventpackage
{
import flash.events.Event;
public class CustomEvent extends Event
{
public static const ENABLED_CHANGED:String = "enabledChanged";
public function CustomEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
}
}
}
Dans un composant MXML
Pour un composant MXML, il faut utiliser le tag <mx:Metadata> directement en tant qu'enfant du nœud principal:
Voici un petit "tip" pour les développeurs Flex qui créent leurs propres composants Flex. Vous le savez, la plupart les classes de Flex peuvent être créées de manière déclarative en MXML. Il en va de même pour les classes AS ou MXML que vous créez vous-même.
Prenons un petit exemple. On crée une classe MenuItem.as qui nous servir à peupler une MenuBar:
package model
{
import mx.collections.ArrayCollection;
public class MenuItem
{
public var label:String = null;
public var children:ArrayCollection = null;
public function MenuItem()
{
}
}
}
La classe est très très simple, on a simplement 2 propriétés, label et children, qui sont des valeurs clé pour Flex quand il va chercher une hiérarchie. En effet, si on donne comme dataProvider, un ArrayCollection contenant des MenuItem, il va chercher la propriété "label" pas défaut pour définir le nom à afficher si on ne lui donne pas de "labelField". Idem pour la propriété "children", c'est dans cette propriété qu'il va chercher des éléments fils.
Pour construire un simple menu tout en MXML, on aura donc:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:local="*" xmlns:model="model.*">
<mx:MenuBar id="menuComponent">
<mx:dataProvider>
<model:MenuItem label="Menu1" >
<model:children>
<mx:ArrayCollection>
<mx:Array>
<model:MenuItem label="SubMenu1"/>
<model:MenuItem label="SubMenu2">
<model:children>
<mx:ArrayCollection>
<mx:Array>
<model:MenuItem label="SubSubMenu1"/>
<model:MenuItem label="SubSubMenu2"/>
</mx:Array>
</mx:ArrayCollection>
</model:children>
</model:MenuItem>
</mx:Array>
</mx:ArrayCollection>
</model:children>
</model:MenuItem>
<model:MenuItem label="Menu2"/>
</mx:dataProvider>
</mx:MenuBar>
</mx:Application>
Cela fonctionne très bien, notre menu s'affiche comme on le voulait. On remarque cependant que c'est plutôt verbeux pour la création d'un menu à plusieurs étages. En effet, quand on veut ajouter des éléments fils, on doit déclarer la propriété "model:children" (ma classe se trouve dans le package "model", puis un mx:ArrayCollection puis un mx:Array.
Mais vous pouvez contourner cela pour alléger votre code en précisant une propriété par défaut (DefaultProperty). Cette propriété est déclarée à l'aide d'un Metatag sur votre classe comme ceci:
package model
{
import mx.collections.ArrayCollection;
[DefaultProperty("children")]
public class MenuItem(){
....
Alors à quoi sert cette annotation? Et bien cette annotation sert à indiquer à Flex quel sera la propriété à utiliser par défaut quand on va ajouter un noeud MXML comme enfant à notre classe/composant. Ici, on précise que l'on souhaite utiliser "children" par défaut. Il n'est donc plus besoin de créer un tag model:children, Flex sait déjà que quand on ajoute des fils, on cherche à modifier la propriété "children".
Pour ne pas avoir de surprises quand on change de plate-formes d'exécution de Flash Player, il est tentant d'embarquer une police de caractère. Ainsi, vous aurez un rendu qui sera (quasiment) le même que vous soyez sur Linux, Mac ou Windows. Il y a plusieurs technique pour embarquer (embed) une font, cet article en fait le point:
Flex Embed Fonts – Polices Embarquées à la compilation
Cependant, de base, Flex va embarquer l'ensemble des caractères de la police. Cela peut être particulièrement encombrant pour la plupart des applications puisque le poids du SWF va gonfler pour pouvoir supporter des caractères que votre utilisateur ne va sûrement jamais utiliser (qui va taper un caractère norvégien avec un clavier français ?).
Pour améliorer cette situation, Flex vous donne la possibilité de restreindre les caractères embarqués en précisant des plages de caractères Unicode. Vous pouvez trouver la liste des caractères Unicode sur Wikipedia:
List of Unicode characters
Par exemple, pour intégrer une font avec seulement les chiffres, vous pouvez écrire dans la déclaration CSS:
unicode-range: U+0030-U+0039;
Ici, on va aller du caractère U+0030 (zero) au caractère U+0039 (neuf).
Pour ne spécifier qu'un caractère, il suffit de créer une plage avec les deux bornes égales.
Pour intégrer uniquement les caractères français, c'est-à-dire les chiffres, les lettres, les lettres en majuscule, la ponctuation et les lettres accentuées, il vous faudrait donc préciser toutes les plages.
Pour vous faciliter la tâche, j'ai déjà fait ce recoupement. Voici donc les codes Unicodes à préciser dans votre unicode-range. L'application sert à tester cette opération. Tapez des caractères, s'il n'apparaissent pas, cela signifie que le caractère n'est pas inclus. Pour l'anecdote, la taille de l'application est passée de 225Ko à 191Ko mais cela peut se révéler beaucoup plus intéressant sur d'autres polices.
Si vous pensez qu'il faille rajouter un caractère, laisser un commentaire, avec le code Unicode si possible pour que je puisse compléter cet exemple:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" viewSourceURL="srcview/index.html">
<mx:Style>
@font-face {
src: url("C:\\Windows\\Fonts\\GOTHIC.ttf");
fontFamily: gothicCentury;
unicode-range: U+0020-U+002F, /* ponctuation */
U+0030-U+0039, /* 0-9 */
U+003A-U+0040,
U+0041-U+005A,
U+005B-U+0060,
U+0061-U+007A, /* a-z */
U+007B-U+007E,
U+20AC-U+20AC, /* euro sign */
U+00A3-U+00A3, /* pound sign */
U+00B2-U+00B2, /* power of 2 */
U+00F9-U+00F9, /* ù */
U+00E0-U+00F6; /* accents */
}
global {
fontFamily: gothicCentury;
}
</mx:Style>
<mx:TextInput id="input" fontSize="20" width="350"/>
<mx:Label text="{input.text}" fontSize="20"/>
</mx:Application>
Flex Source Code Download: Télécharger le code source complet de l'application
This movie requires Flash Player 11