Starling API – 3 – Créer une Texture et afficher une Image
Dans l'épisode précédent, vous avez appris à connaître les classes de base de l'API Starling:
Starling API – 2 – Les classes de base : DisplayObject, Sprite, Quad, Texture et Image
Maintenant que votre projet d'exemple est prêt, on va commencer à coder un peu
.
Ajouter un simple carré de couleur avec Quad
Pour s'échauffer, on va commencer par afficher un carré de couleur grâce à la classe Quad. Très simple, on instancie un objet Quad avec ses dimensions et sa couleur et on l'ajoute à la scène:
package com.fnicollet{
import starling.display.Quad;
import starling.display.Sprite;
public class AquariumScreen extends Sprite{
public function AquariumScreen(){
super();
var q:Quad = new Quad(40, 40, 0xFF0000);
addChild(q);
}
}
}
Click droit sur votre projet > Run as > Web application. Votre navigateur va s'ouvrir et afficher votre carré rouge:
Un magnifique carré rouge. Au moins, cela signifie que Starling fonctionne et que vous n'avez raté aucune étape dans la préparation de votre projet. Bravo
.
Commencer au bon moment
Notre test a fonctionné mais il n'est en fait pas vraiment exact. On est en train de faire notre traitement trop tôt, on n'est pas encore sûr que Starling a terminé d'instancier la classe et l'a ajouté sur la scène. On va donc s'abonner à l'évènement Event.ADDED_TO_STAGE qui va nous indiquer le bon moment pour réaliser nos traitements:
package com.fnicollet{
import starling.display.Sprite;
import starling.events.Event;
public class AquariumScreen extends Sprite{
public function AquariumScreen(){
super();
addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(event:Event):void{
removeEventListener(Event.ADDED_TO_STAGE, init);
// code
}
}
}
Attention, ici Event est la classe starling.events.Event.
Créer un matériau avec Texture
Comme on l'a expliqué dans l'article précédent, vous afficher une Image, vous aurez besoin de créer une Texture. Pour créer une Texture, la classe Texture définit plusieurs méthode static:
- Texture.fromBitmap(data:Bitmap, generateMipMaps:Boolean=true, optimizeForRenderTexture:Boolean=false):Texture
- Texture.fromBitmapData(data:BitmapData, generateMipMaps:Boolean=true, optimizeForRenderTexture:Boolean=false):Texture
- Texture.fromTexture(texture:Texture, region:Rectangle):Texture
Vous ne verrez donc pas de "new Texture" puisque ces méthodes sont static. On va commencer par utiliser la méthode Texture.fromBitmap(…) à laquelle on doit passer un objet de type Bitmap. Pour cela, on va ajouter une texture que j'ai trouvé sur ce site et découpé pour qu'elle soit sur fond transparent (PNG):
Placez ensuite l'image dans un répertoire /assets/spritesheet/ dans votre projet que vous aurez créé au préalable (click droit > New > Folder):
On va maintenant indiquer dans notre code que l'on va compiler cette image et la référencer grâce à une directive Embed:
package com.fnicollet{
import flash.display.Bitmap;
import starling.display.Image;
import starling.display.Quad;
import starling.display.Sprite;
import starling.events.Event;
import starling.textures.Texture;
public class AquariumScreen extends Sprite{
[Embed(source="/assets/spritesheet/mediumguppy.png")]
private static const mediumguppy_imageSpriteSheet:Class;
public function AquariumScreen(){
super();
addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(event:Event):void{
removeEventListener(Event.ADDED_TO_STAGE, init);
// code
}
}
}
Ici, on va récupérer une variable de type Class.
Starling API – 2 – Les classes de base : DisplayObject, Sprite, Quad, Texture et Image
Avant de manipuler l'API Starling, on va apprendre à la connaitre un peu mieux. Dans ce billet, je vais présenter les classes DisplayObject, Sprite, Quad, Texture et Image qui sont les bases des APIs que vous allez manipuler.
Voici un petit récapitulatif de la structure de ces classes:

La classe DisplayObject
La classe DisplayObject représente un élément qui pourra être affiché à l'écran. La plupart du temps, vous n'allez pas utiliser DisplayObject directement mais plutôt une classe qui en hérite comme Sprite ou Image.
DisplayObject contient les propriétés / méthodes communes à la manipulation des objets de la scène:
- x / y : position de l'objet par rapport au parent
- scaleX / scaleY : étirement de l'objet (1 par défaut)
- pivotX / pivotY : Définition de la position du point de pivot de l'objet pour sa rotation
- rotation : Rotation par rapport au point de pivot (en radians et pas en degrés)
- alpha : Opacité de l'objet
- visible : Objet affiché ou non sur la scène (mais pas supprimé)
- touchable : Va répondre ou pas aux clicks / touches
La classe Sprite
Sprite est sûrement la classe que vous allez manipuler le plus. D'ailleurs, dans la préparation du projet, vous avez déjà créé une classe de type starling.display.Sprite, qui est la base de votre scène Starling.
Sprite hérite de DisplayObjectContainer qui hérite de DisplayObject, qui hérite de EventDispatcher. Le fait que Sprite hérite de DisplayObjectContainer fait qu'une Sprite peut aussi contenir d'autresSprite.
La classe Sprite contient notamment (par son héritage de DisplayObjectContainer), les méthodes suivantes pour gérer ses enfants:
- addChild(child:DisplayObject)
- addChildAt(child:DisplayObject, index:int)
- removeChild(child:DisplayObject, dispose:Boolean=false)
- removeChildren(beginIndex:int=0, endIndex:int=-1, dispose:Boolean=false)
- getChildAt(index:int):DisplayObject
- getChildByName(name:String):DisplayObject
- getChildIndex(child:DisplayObject):int
- swapChildren(child1:DisplayObject, child2:DisplayObject)
Pour ajouter un élément à notre scène Starling, on va par exemple utiliser la méthode addChild(…).
La classe Quad
La classe Quad hérite de DisplayObject. Elle peut donc être ajoutée à la scène. Cette classe permet d'ajouter une primitive, un carré de couleur. Son constructeur prend en paramètre une hauteur / largeur et une couleur. Voici un petit code d'exemple pour afficher un carré rouge:
var q:Quad = new Quad(40, 40, 0xFF0000); addChild(q);
On peut aussi régler la couleur de chaque point du carré avec la méthode setVertexColor. La classe Quad n'est pas vraiment la plus utile en soit. Elle peut cependant être pratique pour du debug.
La classe Texture
On commence ici à trouver les classes plus intéressantes que vous allez manipuler. La classe Texture définit un matériau. Ce matériau sera souvent un objet Bitmap que vous allez lui passer.
Elle ne fait que de définir un matériau, une Texture ne peut pas être ajoutée à la scène car Texture n'hérite pas de DisplayObject. Pour afficher une texture, on va la donner à la classe Image (qui hérite de DisplayObject) dont le but sera simplement d'afficher la texture.
Attention cependant à bien utiliser la classe Texture. Chaque fois que vous allez créer une texture, celle-ci va être "uploadée" vers le GPU (carte graphique). C'est une opération rapide mais qu'il ne faut pas multiplier. Vous devrez ré-utiliser les textures au maximum. Une instance de Texture peut par exemple être utilisée par de multiples Image, et c'est ce que vous allez faire le plus souvent
La classe Image
La classe Image est un objet graphique non animé qui va prendre une Texture dans son constructeur. Image va simplement prendre la texture et l'afficher à l'écran. Comme Image est un DisplayObject, vous pourrez la manipuler facilement pour la placer sur la scène.
Contrairement à Texture, vous pouvez créer autant d'instance d'Image que vous le souhaitez. Ce sont les objets Texture qu'il faut essayer d'économiser.
Conclusion
Il existe bien d'autres classes dont on va parler dans les tutoriaux suivants (MovieClip, Tween, …). Les classes présentées dans cet articles vont vous permettre de démarrer, il est utile de bien comprendre qui fait quoi.
Dans le prochain tutorial, on va voir comment créer notre première texture et afficher une image.
AIR Mobile – Application Pokémon (9) – Affichage des informations de base dans la vue détail
Dans le dernier tutorial, on a vu comment passer de la première vue (liste) à la deuxième vue (détail). Cette deuxième vue nommée PokemonDetailsView.mxml est pour l'instant vide mais cette vue va être informé du pokémon sélectionné dans la vue liste, on peut déjà afficher certaines informations relatives à ce Pokemon.
Par la suite, on affichera plus d'informations sur le Pokémon (évolutions, stats, …) basées sur des requêtes SQL supplémentaires que l'on va faire sur la base SQLite.
Récupération de l'objet Pokémon passé depuis la liste
La première étape consiste à récupérer l'objet Pokemon que l'on a passé à la méthode pushView dans la partie précédente du tutorial. Dans le processus classique de pushView, la vue est instanciée puis on lui passe la donnée passée dans pushView dans sa propriété nommée "data". Dans la vue PokemonDetailsView, lorsque l'on ira chercher la propriété "data", on va récupérer notre objet Pokemon.
On pourrait le faire sur l'évènement "creationComplete" ou "viewActivate" de la vue mais on va le faire dès que la propriété "data" est remplie par Flex. Pour cela, on va surcharger le setter de la propriété "data" comme ceci (ajoutez un tag Script avant):
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" title="PokemonDetailsView">
<fx:Script>
<![CDATA[
override public function set data(value:Object):void{
}
]]>
</fx:Script>
</s:View>
Avec ce code, on a "saboté" le setter de data. En effet, si on laisse le code comme cela, on a coupé le comportement de base et on ne fait rien. Il est important de conserver le comportement de base de cette propriété de manière non intrusive, on va donc appeler le "super" de cette propriété pour indiquer que l'on veut réaliser le comportement de base:
override public function set data(value:Object):void{
super.data = value;
}
Voilà, pour l'instant, on a absolument rien changé, c'était pour vous montrer comment surcharger une méthode. Maintenant, on va récupérer la valeur qui est passée à "data" (notre objet Pokemon) et la stocker dans une variable privée de type Pokemon:
import model.Pokemon;
private var _p:Pokemon = null;
override public function set data(value:Object):void{
super.data = value;
_p = Pokemon(value);
}
Modification du titre de la vue
Le titre de la vue de base est donné par la propriété "title" de la vue PokemonDetailsView.mxml. Supprimez cette valeur par défaut, à la place, on va afficher le nom de notre pokémon et son identifiant:
_p = Pokemon(value);
title = _p.nom + " #" + _p.id;
Lancez l'application, sélectionnez un pokémon et vous aurez le rendu suivant:
Affichage de l'image du Pokémon
Dans la 2ème partie du tutorial, vous avez du télécharger une archive contenant toutes les images de pokémons. Décompressez cette archive et placez la dans les sources de votre projet. Les images devraient se situer dans un dossier nommé "images" directement dans src:
Visualisation de la base de données SQLite
Pour l'instant, vous avez travaillé avec la base de données SQLite sans savoir sa structure ni la donnée qu'elle contient. Seulement, pour la suite, vous devrez allez voir quelles sont les données à récupérer et leur format.
AIR pour Android – Récupérer une image issue de la galerie Caméra avec CameraRoll (browseForImage)
La classe CameraRoll, diffusée avec Air 2.5 vous permet d'aller récupérer une photo depuis la galerie native de votre téléphone Android. Les photos que vous prenez avec la caméra ou que vous recevez (par mail par exemple) sont toutes enregistrées dans cette galerie. Sur votre portable, vous pouvez y accéder par l'intermédiaire de l'application "Gallery".
Grâce à l'objet CameraRoll, et notamment à la méthode browseForImage(), votre application Air peut demander au système Android le choix d'une image. C'est alors l'application native Gallery qui prend la main.
Dès que l'utilisateur choisit une image, un évènement de type MediaEvent sera dispatché. S'il a choisit une image, un évènement de type MediaEvent.SELECT sera renvoyé. S'il choisit de ne pas choisir d'image, un évènement de type Event.CANCEL sera propagé.
A partir de cet objet MediaEvent, vous pouvez récupérer un objet de type MediaPromise depuis la propriété "data". Celui-ci n'est pas directement une référence vers un fichier (objet de type File) mais un objet intermédiaire vous permettant de récupérer le fichier par la suite. Une référence vers le fichier est contenu dans la propriété "file".
Une fois que vous avez cette référence vers un objet de type File, vous pouvez récupérer le chemin natif de cette image grâce à la propriété "nativePath". Sur Android, pour une photo issue de l'appareil photo, le chemin est de type "/mnt/sdcard/DCIM/100MEDIA/IMAGxxxx.jpg".
Une fois que vous avez ce chemin, vous pouvez utiliser un Loader pour charger l'objet MediaPromise pour récupérer le résutlat et le mettre dans un objet de type mx:Image par exemple ou le dessiner sur un BitmapData.
Démonstration vidéo !
Roulement de tambour, grande première sur flex-tutorial.fr, une démonstration vidéo ^^! Ce n'est pas encore super au point comme celles de evangelist Adobe qui ont du matos (et des gens pour filmer). J'ai essayé avec mon appareil photo, le résultat est pas vraiment top, sûrement parce qu'il fait rarement jour quand j'écris mes tutos. J'utilise donc un utilitaire pour faire un screencast du rendu de mon téléphone qui me sort un fichier .mov. Ce n'est pas extra-ordinaire mais pour l'instant, cela vous permet de voir ce qui se passe !
Application Exemple
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
/**
* Access the native image gallery
*/
private var _cameraRoll:CameraRoll = null;
/**
* Intermediate object that contain the file
* selected by the user
*/
private var _mediaPromise:MediaPromise = null;
/**
* Loads the nativePath to show it in an image
*/
private var _mediaPromiseLoader:Loader = null;
private function onGetImage():void {
if (!_cameraRoll) {
if (CameraRoll.supportsBrowseForImage) {
_cameraRoll = new CameraRoll;
} else {
showInfo("Fonctionnalité browseForImage non supportée...");
return;
}
_cameraRoll.addEventListener(MediaEvent.SELECT, onSelection);
_cameraRoll.addEventListener(Event.CANCEL, onCancel);
_cameraRoll.addEventListener(ErrorEvent.ERROR, onErrorEvent);
}
// demande de récupération d'image au système Android
_cameraRoll.browseForImage();
}
private function onErrorEvent(event:ErrorEvent):void {
showInfo("Erreur lors de la sélection");
}
private function onCancel(event:Event):void {
showInfo("L'utilisateur a annulé la sélection...");
}
private function onIOError(event:IOErrorEvent):void {
showInfo("Erreur lors de la récupération de la sélection...");
}
private function showInfo(text:String):void {
log.text = text;
}
private function onSelection(event:MediaEvent):void {
_mediaPromise = event.data as MediaPromise;
var nativePath:String = _mediaPromise.file.nativePath;
showInfo("Sélection: " + nativePath);
//Loads the MediaPromise object
_mediaPromiseLoader = new Loader()
_mediaPromiseLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
_mediaPromiseLoader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
_mediaPromiseLoader.loadFilePromise(_mediaPromise);
}
private function completeHandler(event:Event):void {
var content:Bitmap = event.currentTarget.content as Bitmap;
if (!content) {
showInfo("Impossible de récupérer le Bitmap associé");
return;
}
mainImage.source = content;
}
]]>
</mx:Script>
<mx:Style>
global {
font-size: 24;
}
</mx:Style>
<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:Box width="100%">
<mx:Button label="Get Image" click="onGetImage();" height="100%" width="100%" />
<mx:Label id="log" fontSize="18" />
</mx:Box>
</mx:ApplicationControlBar>
<mx:Image id="mainImage" width="100%" height="100%" />
</mx:Application>











