La gestion du focus est un point important à considérer pour plusieurs raisons :
- La représentation du focus à l’utilisateur est un feedback pour aider au répérage.
- Cela augmente l’accessibilité des applications.
- Les designers qui ne sont pas habitués à de l’applicatif négligent souvent ce point.
- Ce détail fait partie intégrante d’une interface. Flex gère de façon native le focus. Il le donne par défaut au premier élément cliquable de la DisplayList. Il le propage ensuite de composant en composant en parcourant l’arbre. L’élément possédant le focus est identifiable grâce à un halo bleu autour de lui. On notera que si on veut enlever tout simplement cet effet, il suffit de spécifier la focusSkin du composant comme ceci :
Button {
focusSkin : ClassReference("mx.skin.ProgrammaticSkin");
}
Par contre, dans le cas d’une application entièrement reskinnée, il conviendra de prendre aussi en compte le design du focus (le bleu ciel d’Adobe s’intègrant mal avec un design recherché…)
Skinning
Commençons par ce point pendant que le sujet est chaud. Flex gère l’affichage du focus par l’intermédiaire de la propriété de style focusSkin comme nous l’avons vu plus haut. Par défaut, c’est la skin du framework qui est utilisée. Il est possible de redéfinir cette skin directement dans vos mxml ou bien dans un fichier css à part. FocusSkin est une classe qui doit hériter de ProgrammaticSkin (ou HaloBorder). Il faut imaginer la skin du focus comme un calque transparent par dessus le composant. “Overridez” la méthode updateDisplayList comme pour n’importe quelle autre skin programmatic et vous pouvez commencer votre création :
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void{
super.updateDisplayList(unscaledWidth, unscaledHeight);
g.clear();
var color : uint = this.getStyle("focusColor");
g.lineStyle(1, color);
g.drawRect(0, 0, unscaledWidth, unscaledHeight)
}
Vous avez ainsi (c’est un exemple basique) une représentation du focus avec une couleur dynamique définie dans votre fichier css. Ceci étant dit, passons à la gestion du focus en lui-même.
Paramétrage
Premièrement, il convient d’identifier exactement les écrans sur lequel on souhaite autoriser le focus à se propager. Une application contient généralement un menu ou un footer ou encore des éléments présents tout au long de la navigation mais qui ne rentre pas forcément dans le worflow métier. Dans les composants les plus hauts de la DisplayList, ceux servant à faire les premiers gros découpages de votre application, nous allons forcer Flex à ne pas leur donner le focus. Les propriétés tabEnabled et tabChildren mis à “false” vont permettre cela. Cela nous autorise donc à restreindre la navigation avec la touche “tab” aux seuls composants réellement métier de l’application. Maintenant, il reste à forcer le focus au premier élément cliquable de chaque écran sur lequels on souhaite naviguer de façon précise avec le clavier. Pour cela, deux lignes de code supplémentaire que l’on pourra ajouter dans le handler de l’évènement show de l’écran par exemple :
private function _onShow() : void{
firstInput.setFocus();
firstInput.drawFocus(); //Force the framework to draw the custom focus skin
}
tabIndex
Cette propriété permet de surcharger l’ordre de navigation. Sauf dans le cas d’écran spécifique, il convient de laisser Flex gérer ce point. En effet, Flex arrête de propager le focus sur les composants non visibles ou désactivés. A partir du moment ou on décide de forcer le tabIndex, il faudra aussi gérer manuellement ce genre de cas.
Interaction avec le navigateur
Par défaut, lorsque le dernier élément de la displayList perd le focus, c’est le premier qui le reprend. Un seul navigateur n’applique pas ce principe, vous avez gagné, c’est Internet Explorer. Ce dernier récupère le focus pour lui, il faudra donc 3 ou 4 appuis supplémentaire sur la touche “tab” pour redonner le focus au Flash Player. Pour remédier à ce problème, il faut faire deux choses : - Ajouter les deux bouts de code javascript et actionscript disponibles ici ; - Appliquer le patch SDK-18150 d’Adobe afin de faire fonctionner correctement la méthode getNextFocusManagerComponent(). De plus, l’exécution de la méthode getNextFocusManagerComponent avec le paramètre backward à “true” donne le focus à l’avant-dernier composant et non au dernier. Il faut donc ajouter une ligne dans le code AS… :
private function _callMe(name:String):void{
if (name == "false") {
focusManager.getNextFocusManagerComponent().setFocus();
} else {
// the combination of SHIFT+TAB has been pressed
focusManager.getNextFocusManagerComponent(true).setFocus();
focusManager.getNextFocusManagerComponent().setFocus(); //Bug with backward=true
}
}
Voici une petite application simple afin d’illustrer cet article (le hack pour gérer la navigation correctement sous IE n’a pas été implémenté dans cet exemple) :
Pour être complet, il faudrait aussi redéfinir les up-skin, down-skin et over-skin afin d’enlever complètement la skin Halo (bleu) de Flex.


