AIR Mobile – Application TweetDeck (8) – Création d'un itemRenderer pour l'objet Tweet
Dans le tutorial précédent, on a vu comment interroger le service Twitter et comment afficher une liste de Tweet dans une liste:
AIR Mobile – Application TweetDeck (7) – Afficher une liste de Tweet
Le résultat est un peu décevant car de base, on ne peut afficher qu'une ligne de texte. Voilà par exemple le rendu d'un tweet sur TweetDeck:
En gros, on a :
- Une photo toujours de la même taille, en haut à gauche
- Un texte multi-ligne (le tweet) avec potentiellement des liens URL
- Un texte sur une ligne (le nom de l'utilisateur)
Sur le screenshot, il y a aussi le nombre de likes et de commentaires, qui est propre à Facebook. On va se limiter à Twitter pour le moment
Classes d'itemRenderer disponibles avec Flex
A partir de là, la grosse erreur que l'on pourrait faire, c'est d'aller coder à la main son itemRenderer de 0. Alors qu'il y a peut-être des classes qui pourraient nous aider. J'avais écrit un article là-dessus sur flex-tutorial.fr:
AIR Mobile – Les itemRenderer de List (LabelItemRenderer, IconItemRenderer, …)
Le composant IconItemRenderer semble parfait pour la tâche puisqu'il a déjà deux labels et une image. Quelques points bloquants cependant:
- Le texte multi-ligne vient en second
- Le texte multi-ligne ne supporte pas les liens URL
On pourrait adapter simplement le design en mettant le texte multi-ligne en bas et ne pas s'en pré-occuper mais pendant qu'on est à faire un clone de TweetDeck, autant faire attention aux détails.
La prochaine partie du tutorial sera un peu "avancée", vous pouvez la sauter si cela vous semble trop complexe.
Création de l'itemRenderer
Pour notre itemRenderer, on va donc hériter de IconItemRenderer. Faites donc un clic droit sur le package "views" > New > ActionScript Class. Nommez cette classe "TweetRenderer", Based On IconItemRenderer puis finish. Pour pouvoir effectuer nos tests, on va directement l'assigner sur notre liste:
<s:List width="100%" height="100%" dataProvider="{searchResult.lastResult.results}"
labelField="from_user">
<s:itemRenderer>
<fx:Component>
<views:TweetRenderer iconField="profile_image_url"
labelField="from_user"
messageField="text" />
</fx:Component>
</s:itemRenderer>
</s:List>
Voici le rendu provisoire:
Première étape: inversion du label et du message
Pour commencer, on va inverser la position des deux textes. Il faut bien faire attention que le texte du message est multi-ligne, la hauteur de l'itemRenderer est donc conditionnée par ce composant. Tout se passe dans la méthode "layoutContents" qui fait le calcul des tailles et du placement des éléments. On va surcharger cette méthode et inverser la position des éléments.
Pour éviter de vous taper la signature de la méthode layoutContents, on va utiliser une fonctionnalité de Flash Builder. Sur l'éditeur de code de TweetRenderer, faites clic droit puis Source puis Override / Implements methods…:
Cochez la méthode layoutContents et validez. Moins de risques d'erreur de cette manière. Dans la classe de base, on va récupérer un bout de code qui nous sera utile:
var hasLabel:Boolean = labelDisplay && labelDisplay.text != ""; var hasMessage:Boolean = messageDisplay && messageDisplay.text != "";
Comme cela, on a la détection de la présence ou pas des composants. Dans notre cas, on cherche juste à faire le switch quand le renderer dessine les 2 composants:
package views{
import spark.components.IconItemRenderer;
public class TweetRenderer extends IconItemRenderer{
public function TweetRenderer(){
super();
}
override protected function layoutContents(unscaledWidth:Number, unscaledHeight:Number):void{
super.layoutContents(unscaledWidth, unscaledHeight);
var hasLabel:Boolean = labelDisplay && labelDisplay.text != "";
var hasMessage:Boolean = messageDisplay && messageDisplay.text != "";
if (hasLabel && hasMessage){
var labelY:Number = labelDisplay.y;
var messageY:Number = messageDisplay.y;
messageDisplay.y = labelY;
labelDisplay.y = labelY + messageDisplay.height;
}
}
}
}
Voici le rendu:
Bon, voilà, c'était assez simple pour cette partie. Maintenant, on va essayer d'afficher les liens URL différemment.
Deuxième étape : Afficher les liens URL
Autant la première étape était simple, autant la 2ème est plus corsée. Le service Twitter vous renvoie un contenu texte brut. Ce n'est pas du html, par exemple on a "Woo! I got 100% on the Adobe Illustrator quiz. Try it! http://t.co/mrE3QOo via @envatovectors". La première mission va être de détecter ces liens dans le texte pour pouvoir les afficher différemment.
Pour ce genre de mission (recherche de chaîne dans une chaîne), et dans tous les langages, vous devriez avoir un premier réflexe : les expressions régulières. C'est l'arme parfaite pour s'attaquer à ce genre de problèmes. Mais si comme moi, vous n'êtes pas un "regexp-wizard", même détecter une URL dans un texte devient difficile.
Détecter le click sur un lien dans un texte HTML (TextEvent.LINK)
Tutorial Flex écrit par Laurent Wroblewski (http://flex-ria.fr/)
Publiez vous aussi sur flex-tutorial!
Vous utilisez le composant Flex Label (ou les composants qui l'étendent, comme Text), et vous souhaitez pouvoir réagir à un clic sur une portion
de son contenu? Pas si simple!
Imaginons un label doté du texte suivant : "Ceci est un exemple de LIEN vers une image!". Vous souhaitez qu'un clic sur le mot "LIEN" entraîne l'affichage d'une image à l'écran. Pour ce faire, nous allons passer par la propriété htmlText du composant et utiliser des balises HTML <a> pour encadrer le mot "LIEN". Seul petit problème, en utilisant cette balise de manière traditionelle (ex : <a href='assets/test.jpg'>), un clic sur le texte redirigera la page vers le lien inséré (dans notre exemple, vers
l'image assets/test.jpg). Pas vraiment ce que nous voulons...
L'astuce ici est d'utiliser cette syntaxe :
<a href='event:assets/test.jpg'>
Ainsi, un clic sur le texte entraînera le dispatch d'un événement de type TextEvent.LINK depuis votre composant Label, que vous aurez tout loisir de capturer au sein d'un handler pour effectuer un traitement de votre choix.
IMPORTANT : pour qu'un événement de type TextEvent.LINK soit dispatché depuis un Label, la propriété selectable de celui-ci doit être à true.
<mx:Script> <![CDATA[ private function txtExemple_LinkHandler(evt:TextEvent):void { trace(evt.text); } private function txtExemple_InitializeHandler(evt:Event):void { this.txtExemple.htmlText = "Ceci est un exemple de <a href='event:assets/test.jpeg'>LIEN</a> vers une image!"; } ]]> </mx:Script> <mx:Text id="txtExemple" initialize="txtExemple_InitializeHandler(event)" link="txtExemple_LinkHandler(event)" selectable="true" />
Dans l'exemple ci-dessus, en imaginant que l'utilisateur clique sur le mot "lien" du texte du composant txtExemple, un événement de type TextEvent sera dispatché, dont la propriété text sera égale à assets/test.jpeg. Après, libre à vous d'effectuer le traitement que vous souhaitez.
L'exemple ci-dessous va créer une image dont l'url sera renseignée dans le lien, et l'afficher dans l'application à la position du pointeur de la souris.
Un second clic sur l'image fera disparaître celle-ci. Attention, pour que l'image se positionne correctement, il faut que son container (dans mon cas l'Application) ait un layout de type absolute (un Canvas par exemple).
private var _image:Image;
private function txtExemple_LinkHandler(evt:TextEvent):void
{
if (!this._image)
{
this._image = new Image();
this.addChild(this._image);
}
this._image.source = evt.text;
this._image.x = this.contentMouseX;
this._image.y = this.contentMouseY;
this._image.visible = this._image.includeInLayout = true;
this._image.useHandCursor = this._image.buttonMode = true;
this._image.addEventListener(MouseEvent.CLICK, image_ClickHandler, false, 0, true);
}
private function image_ClickHandler(evt:MouseEvent):void
{
this._image.visible = this._image.includeInLayout = false;
}
Exemple en ligne
Flex Source Code Download: Télécharger le code source complet de l'application
Flex Tips – Obtenir un texte HTML valide à partir du RichTextEditor (htmlText)
Le composant Flex RichTextEditor permet d'avoir un champ texte "riche", c'est-à-dire avec des options de formatage un peu comme celles qu'on trouve dans Word (gras, souligné, alignement, puces...). Ce composant peut-être très pratique pour laisser un utilisateur créer du contenu HTML facilement, sans qu'il ne sache comment écrire du HTML, pour un CMS par exemple ou une plate-forme de blog.
Le composant RichTextEditor (RTE) a une propriété "htmlText", qui permet d'assigner du texte HTML et une propriété "text" qui permet d'avoir le contenu brut, sans balises.
Si par exemple, vous écrivez dans votre RichTextEditor:
This is <b> Bold </ b> text.
Vous obtiendrez par la propriété "htmlText", quelque chose comme:
<TEXTFORMAT LEADING="2"> <P ALIGN="LEFT"> <FONT FACE="Verdana" SIZE="10" COLOR="#0B333C" LETTERSPACING="0" KERNING="0"> This is <b> Bold </b>text. </FONT> </P> </TEXTFORMAT>
Comme vous le voyez, Flex rajoute beaucoup de code HTML non-nécessaire. De plus, ce code pseudo-html ne sera pas interprété par une page HTML classique (TEXTFORMAT n'est pas une balise HTML par exemple).
Dans notre cas, on veut que le contenu HTML inscrit par l'utilisateur soit directement utilisable pour une intégration dans du HTML. Certains ce sont posé la question, sur le blog Thanks Mister. La solution se trouve dans les Expressions Régulières AS3. Avant de passer aux choses sérieuses, voici quelques articles qui devraient vous aider à comprendre les RegExp:
Adobe Air – Composant mx:HTML avec contenu SWF et Garbage Collection
Aujourd'hui, je suis tombé sur cet article de Gregory Wilson expliquant les problèmes de fuites mémoire (memory leak) rencontrés avec l'application Adobe Air Tour de Flex. Pour ceux qui ne connaissent pas Tour de Flex, c'est une application Air pour montrer les capacités du SDK Flex avec des applications exemple (et le code source). Si vous ne l'avez pas encore sur votre poste, je vous la conseille vivement:
Télécharger l'application Tour de Flex (Adobe Air)
L'application Tour de Flex utilise un composant <mx:HTML> (qui fait partie du SDK Air) permettant d'afficher des pages HTML dans une application. Dans ce cas précis, il est surtout utilisé pour afficher du contenu SWF (pris depuis un page HTML classique). Si vous jouez un peu avec l'application, vous vous rendrez compte qu'elle monte très rapidement en RAM, à cause principalement d'une fuite mémoire (Memory Leak).
Au passage, si vous voulez en apprendre plus sur la gestion des ressources AS3 et le Garbage Collector, je vous conseille vivement de lire ces articles:
Flex Debug - Garbage Collector AS3 et Flash Player 9
Flex Debug - Garbage Collector AS3: Gestion des ressources
Gregory Wilson a donc identifié cette fuite mémoire du composant <mx:HTML> et cela pourra vous être utile si votre application Adobe Air utilise elle aussi ce composant. Pour résumer le problème, si un composant mx:HTML charge une page avec du contenu Flash (SWF), le composant ne peut pas être libéré d'un point de vue mémoire, même si vous le supprimez de son conteneur, lui enlevez ses références, etc. Le contenu Flash continue de s'exécuter.
Pour résoudre ce problème, il faut fixer l'attribut "htmlText" à une chaîne vide("") et le Garbage Collector pourra passer.









