AIR pour BlackBerry – La problématique du menu
Malgré une sortie qui parait peu lointaine (Q1 2011, vraisemblablement Janvier aux US), le BlackBerry Playbook reste encore très mystérieux. Peu ont eu la chance de pouvoir en approcher un et encore moins ont eu la chance de pouvoir le manipuler.
J'étais un workshop BlackBerry Playbook la semaine dernière à LeWeb'10, en pensant pouvoir en manipuler un mais la réponse a été "j'en ai un mais je ne peux pas vous le montrer". Il est donc difficile de savoir à quoi ressemble le BlackBerry Playbook, notamment au niveau des applications livrées de base. Le simulateur BB Playbook est pour le moment livré vierge de toute application, difficile donc de se faire un idée.
Il y a un élément qui reste le plus étrange, c'est le menu. Selon ce qui s'est dit dans les webcasts, s'il on fait un slide de bas en haut de la tablette (sur la partie haute de la tablette), cela devrait apparaître un menu. Voici ce qui est dit dans les UI Guidelines:
"Use a menu bar to move UI components off the screen
The application menu can include primary or secondary
Display the menu when dragging from the top of the screen"
Sauf que ce menu, il faut le faire par soi-même, il n'y a pas de composant Menu dans les packages QNX, ou tout du moins, pas encore.
Alors il faut aller à la pêche aux infos. Une première piste sur le forum BB:
Confused regarding the menubar mentioned in the UI designs
On nous confirme bien qu'il faut créer son propre sous-menu et avec en prime, une vidéo montrant ce menu en action. Cela ne dure pas longtemps, il faut chopper le moment au vol (à -13:45):
MAX 2010: Developing Adobe AIR apps for the BlackBerry Tablet OS
Et voici le moment de la vidéo qui nous intéresse:
On peut aussi le voir rapidement sur cette vidéo (5:00):
A vue de nez, les menu / sous-menus sont imbriqués pour ne garder qu'une seule ligne (contrairement à Android qui n'a pas de sous-menus mais dont les menus peuvent se mettre sur plusieurs lignes.
Personnellement, je ne trouve pas ça très malin car les premières applications qui vont sortir vont être toutes différentes et on n'aura pas au final la même homogénéité que sur iOS ou Android.
Voilà, j'ai contacté le présentateur pour avoir les sources, dans sa démo, ce n'est qu'un Bitmap pour faire croire à un menu, rien d'interactif. Voici son commentaire:
Yes in my example it was just one big bitmap to demonstrate the functionality. We don’t have a menu component per se as we wanted developers to be able to customize it as they see fit.
AIR pour Android – Détecter l'appui sur les boutons BACK, MENU et SEARCH (hardware)
Grâce à l'API Air 2.5, vous pouvez détecter l'appui sur les boutons "hardware" du téléphone. Ce sont les boutons présents sur tous les portables Android.
Ainsi, vous pouvez détecter les appuis sur MENU, BACK et SEARCH. Vous ne pouvez pas détecter l'appui sur HOME, car celui-ci est une "porte de sortie" pour toute application.
Dans le comportement normal d'une application, le bouton BACK vous renvoie vers l'écran ou l'application précédente. Pour une application Air, cela va automatiquement vous faire sortir de l'application, sauf si vous appelez la méthode "preventDefault" sur le KeyboardEvent renvoyé. Dans ce cas-là, l'utilisateur ne sortira pas de l'application.
Ainsi, vous pourrez recréer facilement le comportement des applications natives qui "push" et "pop" des vues les unes au dessus des autres. Une fois le composant ViewNavigator de Hero sorti, vous pourrez, au moment de l'appui sur BACK, faire un "pop" de la vue pour revenir à la vue précédente.
Code de démonstration
Voici une petite application qui vous montre comment écouter les évènements clavier de votre application. Notez que vous devez ajouter le listener au moment de l' APPLICATION_COMPLETE et pas du CREATION_COMPLETE pour que la variable stage soit initialisée correctement
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" paddingLeft="0" paddingRight="0"
paddingTop="0" paddingBottom="0"
applicationComplete="application1_applicationCompleteHandler(event)">
<mx:Style>
global {
font-size: 24;
}
</mx:Style>
<mx:Script>
<![CDATA[
import mx.events.FlexEvent;
/**
*
*/
protected function application1_applicationCompleteHandler(event:FlexEvent):void {
this.stage.addEventListener(KeyboardEvent.KEY_DOWN, downHandler);
}
public function downHandler(event:KeyboardEvent):void {
switch (event.keyCode) {
case Keyboard.BACK:
// to prevent app going to background use following
if (preventCB.selected) {
event.preventDefault();
}
showInfo("BACK key");
//do action related to BACK key
break;
case Keyboard.SEARCH:
//do action related to SEARCH key
showInfo("SEARCH key");
break;
case Keyboard.MENU:
//do action related to MENU key
showInfo("MENU key");
break;
default:
break;
}
}
private function showInfo(text:String):void {
log.text += text + "\n";
}
]]>
</mx:Script>
<mx:ApplicationControlBar left="0" right="0" bottom="0" height="80" paddingTop="8" paddingLeft="8"
paddingBottom="8" paddingRight="8" horizontalGap="8" verticalGap="8"
dock="true">
<mx:CheckBox id="preventCB" label="Prevent Default Home Button" />
</mx:ApplicationControlBar>
<mx:TextArea id="log" backgroundColor="white" width="100%" height="100%" enabled="false" />
</mx:Application>
Télécharger le projet au format FXP
Télécharger l'application au format APK
Flex MenuBar – Bug lors de l'utilisation de sous-menus multiples ne comportant qu'un enfant
Voici un bug de Flex 3 "quasi" impossible à corriger. Après y avoir passé une après-midi complète, j'ai trouvé une solution de remplacement, pas très belle mais qui fonctionne (sous certaines conditions). J'ai pourtant bien cherché sur le net, il semble que personne ne soit tombé sur ce bug, pourtant facile à reproduire.
Si vous avez une solution plus "propre", n'hésitez pas à la soumettre
.
Le Bug en question se produit lors de l'utilisation d'un composant MenuBar. Celui-ci prend un dataProvider hiérarchique (XML ou ArrayCollection).
Notez que les classes suivantes ont été créées pour l'exemple. Dans la vraie vie, on fera peut-être plus attention sur certains points.
Dans notre exemple, on va prendre la classe Model suivante:
package {
import mx.collections.ArrayCollection;
[Bindable]
[DefaultProperty("children")]
public class MenuItem {
public function MenuItem() {
}
public var label:String = null;
public var type:String = null;
public var children:ArrayCollection = null;
}
}
On a ensuite notre application utilisant une MenuBar. Celle-ci est remplie avec des MenuItem, de manière hiérarchique:
- Menu 1
- Menu 2
- Sub Item 1
- Sub Sub Menu 1
- Sub Sub Sub Menu 1
- Sub Sub Menu 1
- Sub Item 1
- Menu 3
Dans notre application, on construit donc ce menu:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:local="*"
viewSourceURL="srcview/index.html">
<mx:MenuBar>
<local:MenuItem label="Menu 1"/>
<local:MenuItem label="Menu 2">
<mx:ArrayCollection>
<local:MenuItem label="Sub Menu 1">
<mx:ArrayCollection>
<local:MenuItem label="Sub Sub Menu 1">
<mx:ArrayCollection>
<local:MenuItem label="Sub Sub Sub Menu 1"/>
</mx:ArrayCollection>
</local:MenuItem>
</mx:ArrayCollection>
</local:MenuItem>
</mx:ArrayCollection>
</local:MenuItem>
<local:MenuItem label="Menu 3"/>
</mx:MenuBar>
</mx:Application>
Et voici le résultat:
Flex Source Code Download: Télécharger le code source complet de l'application
Vous l'avez peut-être remarqué, on a perdu "Sub Sub Menu 1" en route! Mais voici un deuxième exemple plus troublant. On rajoute un item au même niveau que Sub Sub Menu 1, que l'on va appeler Sub Sub Menu 2:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:local="*"
viewSourceURL="srcview/index.html">
<mx:MenuBar>
<local:MenuItem label="Menu 1"/>
<local:MenuItem label="Menu 2">
<mx:ArrayCollection>
<local:MenuItem label="Sub Menu 1">
<mx:ArrayCollection>
<local:MenuItem label="Sub Sub Menu 1">
<mx:ArrayCollection>
<local:MenuItem label="Sub Sub Sub Menu 1"/>
</mx:ArrayCollection>
</local:MenuItem>
<local:MenuItem label="Sub Sub Menu 2"/>
</mx:ArrayCollection>
</local:MenuItem>
</mx:ArrayCollection>
</local:MenuItem>
<local:MenuItem label="Menu 3"/>
</mx:MenuBar>
</mx:Application>
Voici le résultat:
Flex Source Code Download: Télécharger le code source complet de l'application
Notre "Sub Sub Menu 1" est de retour... C'est à partir de ce moment, qu'il faut commencer à s'accrocher car comme vous l'avez vu, on utilise le composant de base de Flex 3 MenuBar. Pour trouver la cause du problème, il va donc falloir aller fouiller dans le code source de Flex à grands coups de point d'arrêt.
Composant Flex – Menu avec Scroll vertical (et MenuBar, PopUpMenuButton)
Quand vous créez une application Flex, vous avez plusieurs moyens de faire apparaître des menus. Pour cela, il y a les composants MenuBar, PopUpMenuButton par exemple. Ces deux composants utilisent une classe de base la classe Menu. La classe Menu du framework peut être utilisée pour afficher des menus n'importe où dans votre application.
Seulement, les menus crées avec la classe Menu ne tiennent pas compte du nombre d'éléments dans un menu ou dans un sous-menu. Ainsi, si vous avez une grande quantité d'éléments et que la hauteur du menu est supérieure à la hauteur de votre application, vous ne verrez pas certains éléments et vous n'aurez aucun moyen d'y accéder (pas de défilement).
Doug McCune a pour cela crée un composant baptisé ScrollableMenu qui affiche des flèches de défilement et/ou des barres de défilement (scrollbar). Tous ces composants sont facilement personnalisables. Les composants ScrollableMenuBar et ScrollablePopUpMenuButton sont eux aussi inclus dans le projet et implémente le même comportement que le ScrollableMenu.
Voir la page officielle sur le blog de Doug McCune
Application de démonstration
Flex Source Code Download: Télécharger le code source complet de l'application
Flex PopUpButton – Menu en PopUp avec une XMLListCollection et labelField
Utilisation de mx.controls.Menu
Les Menus sont des instances de mx.controls.Menu. Comme les Flex Tree, les menus requièrent des data providers hiérarchiques. Le code suivant crée un menu et le peuple avec un dataProvider de type XMLListCollection. Il fixe aussi la propriété labelField, comme on le fait pour un composant Tree:
var menu:Menu = new Menu();
var xmlList:XMLList = XMLList('<item label="ActionScript"><item label="Classe"/><item label="Interface"/></item><item label="MXML"><item label="Application"/><item label="Component"/></item>');
menu.dataProvider = new XMLListCollection(xmlList);
menu.labelField = "@label";





