AIR Mobile – Application Pokémon (27) – Utilisation d'images différentes suivant les DPI (MultiDPIBitmapSource)
Dans notre application, on utilise seulement quelques images. Celles-ci sont au format 32×32 pixels. Par exemple, on a la flèche de retour, le speaker pour le son, l'icône de liste, … Jusque là, on a pas pris en compte la problématique des DPIs. Les DPI représentent la densité de pixels par pouce.
C'est à dire que sur une unique physique (1 pouce), vous pouvez avoir un nombre de pixels différents suivant la densité de pixels de l'appareil. Cette densité varie donc pour chaque appareil.
Voici pour rappel, quelques valeurs de DPI (ou PPI) pour un certain nombre de devices:
Mais pour faciliter la programmation, Adobe a déterminé des "catégories" de DPI, c'est à dire des classes de DPI:
- 160
- 240
- 320
Pour déterminer à quelle classe de DPI appartient un appareil, le runtime consulte la valeur renvoyée par l'appareil et prend la classe de DPI la plus proche.
Quelle taille donner aux assets?
Suivant la densité de votre périphérique, si vous laissez un icône 32×32, celui-ci sera soit gros, soit minuscule. Sur un iPhone 4 par exemple, qui rentre dans la 3ème catégorie de DPI (high DPI), votre icone sera minuscule car sur un pouce, l'iPhone fera rentrer plus ou moins 320 pixels.
D'après mes tests sur plusieurs devices, j'utilise pour mes icônes, les tailles suivantes:
- 24 x 24 pour du DPI 160
- 32 x 32 pour du DPI 240
- 48 x 48 pour du DPI 320
Ce n'est pas proportionnel (bizarrement) mais ça rend plutôt bien.
Définition d'images avec MultiDPIBitmapSource
Pour faire automatiquement le switch, Flex vous propose une nouvelle API nommée "MultiDPIBitmapSource". Celle-ci vous permet d'utiliser plusieurs images pour la même propriété. Flex fera automatiquement le switch suivant le DPI.
AIR SQLite – Embarquer une base SQLite pré-remplie dans une application AIR
Dans les tutoriaux AIR SQLite précédent, on a vu comment manipuler une base de données SQLite avec les APIs AIR. Ainsi, on a pu créer une base de données, créer des tables, insérer des enregistrements, etc. Dans chacun de ces exemples, on est partis de rien et on a crée de la donnée. Dans votre contexte applicatif, le schéma d'utilisation sera sûrement différent.
Par exemple, vous avez des commerciaux nomades qui vont partir avec leur application AIR, sans pouvoir accéder à Internet. Ils ne pourront donc pas requeter votre serveur web pour récupérer des informations. Ou vous voulez leur livrer directement une base produit, sans qu'ils n'aient besoin de synchroniser leur application. Ou vous voulez tout simplement avoir une base de données pré-paramétrées avec votre structure (tables / champs) directement dans votre application pour éviter de devoir faire patienter l'utilisateur lors du premier lancement.
Bref, de nombreuses raisons peuvent vous obliger à embarquer un base SQLite. Rassurez-vous, c'est possible et assez simple mais il y a quelques points auxquels il faut faire attention.
Embarquer une base SQLite dans une application AIR (embedded)
Avant toute chose, il vous faudra disposer de la base que vous souhaitez embarquer. Une base SQLite se présente sous la forme d'un fichier. Vous pouvez créer cette base à l'aide d'une application AIR par exemple. Au final, vous aurez un fichier, que l'on va appeler "employees.db" dans les instructions suivantes. Vous pouvez nommer ce fichier comme vous le souhaitez bien sûr.
Placez ensuite ce fichier dans votre projet, au moins dans le dossier "src". Vous pouvez bien sûr le mettre dans un package. Ici, nous allons mettre notre fichier dans "employees.db" dans le package "db":
Au moment du packaging AIR en release, assurez-vous bien que votre fichier est dans le package (si vous compilez en ligne de commande, ajoutez-le comme source path supplémentaire):
Voilà, votre fichier sera contenu dans votre package .AIR. Voyons maintenant comment l'utiliser.
Utiliser une BDD SQLite embarquée
Lorsque vous placez des fichiers avec l'application dans le package applicatif comme vous venez de le faire, ceux-ci sera accessible dans le répertoire lié à l'application une fois installée (ex C:\Users\fab\AppData\Roaming\YourApp\…). Vous pouvez facilement accéder à ces fichiers grâce à une variable présente (de manière static) sur la classe File. Cette variable est nommée "applicationDirectory" et pointe sur l'endroit du disque sur lequel les fichiers sont conservés.
Pour récupérer une référence vers notre fichier "employees.db", il vous suffit de faire:
var dbFile:File = File.applicationDirectory.resolvePath("db/employees.db");
Jusque là tout va bien, sauf que vous ne pouvez pas travailler directement avec ce fichier car les fichiers présents dans "applicationDirectory" sont en lecture seule. Si vous essayez de lire ou de mettre à jour cette base, rien ne va se passer.
Flex Tips – Embed Font sur un TextField qui n'apparait pas
Un mini-post qui pourrait aider quelques Flexeurs sur un comportement assez étrange quand on utilise des polices embarquées (Embedded). Le code parait bon, pas d'erreur de compilation ni d'exécution mais pourtant le texte n'apparaît pas. J'ai bloqué une petite demi-heure sur ce bug stupide, cela vous arrivera peut-être ^^.
Voici le code que j'avais (réduit):
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="onCreationComplete();"
xmlns:comp="comp.*"
xmlns:local="*">
<mx:Script>
<![CDATA[
import com.bg.BasicFontAssets;
[Embed(systemFont='Arial', fontName='ArialR', mimeType='application/x-font', unicodeRange="U+0020-U+002F, U+0030-U+0039, U+003A-U+0040, U+0041-U+005A,U+005B-U+0060, U+0061-U+007A, U+007B-U+007E,U+20AC-U+20AC, U+00A3-U+00A3, U+00B2-U+00B2,U+00F9-U+00F9, U+00E0-U+00F6")]
public static var ArialR:Class;
private function onCreationComplete():void {
var format:TextFormat = new TextFormat;
format.font = "ArialR";
format.color = 0xFFFFFF;
format.size = 20;
var tf:TextField = new TextField;
tf.embedFonts = true;
tf.autoSize = TextFieldAutoSize.LEFT;
tf.antiAliasType = AntiAliasType.ADVANCED;
tf.text = "Text de test";
tf.defaultTextFormat = format;
uiComp.addChild(tf);
}
]]>
</mx:Script>
<mx:UIComponent id="uiComp"
rotation="10"/>
</mx:Application>
Tout parait OK et pourtant rien de s'affiche. Le bug se situe en fait au moment de l'assignation du "defaultTextFormat". Celle-ci (qui indique que le font est Embed), est faite après l'assignation de la propriété "text". Pour résoudre ce bug, il suffit de:
- Assigner "defaultTextFormat" avant "text"
- ou faire l'assignation à la main: tf.setTextFormat(format).
A ce moment-là, votre champ texte va apparaître avec votre texte et vous pouvez passez au bug suivant
.
Flex Tips – Le Metatag Event pour déclarer la propagation d'un évènement par un composant AS / MXML
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:
Flex Tips – Font Embed avec seulement les caractères français (French Unicode)
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:
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








