Apache Adobe Flex TutorialTutoriaux Adobe Flex & AIR en Français

2déc/114

AIR Mobile – Changer de skin pour ne pas utiliser StageText pour Android (Flex 4.6)

Le comportement des champs texte (TextArea / TextInput) dans une application AIR a toujours été un point difficile. Avant Flex 4.6, le champ texte sous iOS utilisait un composant nommé StageText qui est en fait un composant texte natif iOS, plaqué par dessus la Display List traditionnelle de votre application. Grâce à une skin spéciale, cette feinte ne se voit pas dans votre code, vous allez toujours instancier un composant TextInput.

L'utilisation de champs de texte natifs apportent de nombreux avantages. Tout d'abord, on profite des interactions natives de la plateforme. Sous iOS par exemple, vous aurez les boutons permettant de copier / coller ou de sélectionner facilement du texte. Un comportement qui est naturel pour l'utilisateur et qu'il convient de garder.

Sur Android par contre, on avait toujours des champs texte non-natifs, de simples champs texte donc. Vous n'aviez pas la possibilité de copier / coller un texte par un appui long par exemple. Cela pouvait parfois être très gênant, surtout sur tablette quand on a besoin de sélectionner une partie du texte. Les "poignées" de sélection n'apparaissent pas et l'utilisateur ne pouvait donc rien faire.

Ce manque a été comblé avec la sortie de Flex 4.6 qui propose une skin StageText pour Android. Cette skin sera utilisée par défaut si vous compilez avec Flex 4.6. Vous pouvez retrouver ce paramétrage dans les sources du framework, dans le dossier:

C:\Program Files (x86)\Adobe\Adobe Flash Builder 4.6\sdks\4.6.0\frameworks\projects\mobiletheme

Vous trouverez un fichier nommé defaults.css qui contient:

TextArea{
    paddingBottom: 9;
    paddingLeft: 9;
    paddingRight: 9;
    paddingTop: 9;
    showPromptWhenFocused: true;
    skinClass: ClassReference("spark.skins.mobile.StageTextAreaSkin");
}

TextInput{
    paddingBottom: 9;
    paddingLeft: 9;
    paddingRight: 9;
    paddingTop: 9;
    showPromptWhenFocused: true;
    skinClass: ClassReference("spark.skins.mobile.StageTextInputSkin");
}

On référence bien les skins de type StageText.

Comment ne pas utiliser StageText

Cette skin est donc très bonne mais le problème est que son comportement est assez tiré par les cheveux. On peut donc parfois constater certains bug d'affichage. C'est ce qui est arrivé à peu près 4h après la sortie de Flex 4.6 à un lecteur de flex-tutorial :) . Lors d'une transition, le champ texte (fond) de déplace bien mais le texte (glyphes) restent à la même place jusqu'à la destruction de la vue et donc du composant.

C'est un bug qui devrait être corrigé mais entre temps, il vous reste une porte de sortie. Vous pouvez en effet, indiquer dans votre code que vous souhaitez utiliser la skin "classique" qui était utilisée en Flex 4.5. Pour cela, dans votre application principale, ajouter les sélecteurs de style CSS suivants:

s|TextInput{
  skinClass: ClassReference("spark.skins.mobile.TextInputSkin");
}
s|TextArea{
  skinClass: ClassReference("spark.skins.mobile.TextAreaSkin");
}

Vous allez ainsi utiliser l'ancienne skin sous Android. Cela peut vous permettre de fonctionner en attendant que les bugs présents dans votre application soient corrigés.

Ces bugs devraient être rares, de nombreux bugs ont déjà été rentrés pendant la prerelease sur ces problématiques. Pour vous donner une idée, lorsque vous ouvrez un composant Callout (pop-up non modale) qui passe par dessus un composant texte, pour ne pas avoir de bug graphique, Flex prend automatiquement un "screenshot" du champ texte et remplace le champ texte par cette représentation dans la display list pour qu'elle puisse passer dessous (idem pour StageWebView).

Allez voir dans le code source si vous ne me croyez pas :) .

Remplis sous: Non classé 4 Commentaires
18août/114

AIR Mobile – Skinner un TextInput de façon programmatique

Tutorial Flex écrit par Arnaud Thorel (@athorel)
Publiez vous aussi sur flex-tutorial!

Depuis la version 4.0 de Flex, nous pouvons développer des skins en utilisant la nouvelle structure de composants spark.
Spark propose un système basé sur des composants logiques et des représentations graphiques que l’on appelle Skin. Dans un premier temps la plupart des skins étaient des représentations MXML où venaient se superposer des groupes de primitives de dessins (border, background, shadow, …), mais avec l’avènement du développement mobile, les enjeux de rapidité d’exécutions et de poids des fichiers rentrent en jeu.
C’est ainsi qu’Adobe a mis en place un ensemble de skins pour mobile dont la chaîne d’héritage est nettement moins longue que pour les skins sparks de base.

Dans ce tutorial nous allons voir comment intégrer un titre pour un composant TextInput (comme sur iOS), pour obtenir le rendu suivant, cet exemple pourra servir de base afin d’ajouter d’autres informations dans notre composant (Icon, Aide).

Comprendre l’affichage actuel d’un composant TextInput

Le composant TextInput possède 4 états :

  • Enable : Cet état est l’état éditable d’un TextInput
  • Disable : Cet état est l’état non éditable d’un TextInput
  • EnableWithPrompt : Cet état est l’état éditable d’un TextInput avec une valeur vide
  • DisableWithPrompt: Cet état est l’état non éditable d’un TextInput avec une valeur vide

La première étape consiste à hériter de la classe spark.skins.mobile.TextInputSkin pour obtenir une notre classe PromptTextInputSkin, et ensuite analyser le comportement de TextInpuitSkin.

Tout de suite on se rend compte du coté manichéen du composant TextInput, la valeur vient effacer le prompt, ce qui se traduit dans le code de cette manière.

override protected function commitCurrentState():void
{
    super.commitCurrentState();

    alpha = currentState.indexOf("disabled") == -1 ? 1 : 0.5;

    var showPrompt:Boolean = currentState.indexOf("WithPrompt") >= 0;

    if (showPrompt && !promptDisplay)
    {
        promptDisplay = createPromptDisplay();
        addChild(promptDisplay);
    }
    else if (!showPrompt && promptDisplay)
    {
        removeChild(promptDisplay);
        promptDisplay = null;
    }

    invalidateDisplayList();
}

Lors d’un changement d’état la fonction commitCurrentState on retrouve les éléments suivants :

  • On vérifie si nous sommes dans un état disabled, pour modifier l’alpha du composant.
  • On vérifie si nous sommes dans un état WithPrompt, si c’est le cas et que le prompt n’est pas déjà affiché, il est créé et ajouté, sinon il est retiré si il était déjà présent.
  • On conclut cette fonction par l’appel à invalidateDisplayList qui va permettre l’appel à updateDisplayList qui redessinera le composant

Redéfinir le comportement en fonction de l'état courant

Dans cette méthode on vient d’identifier la partie qui va nous poser problème, la première étape consiste donc à redéfinir cette méthode dans notre classe.

override protected function commitCurrentState():void
{
    alpha = currentState.indexOf("disabled") == -1 ? 1 : 0.5;
    invalidateDisplayList();
}

Nous avons ici de façon volontaire supprimé l’appel à la fonction super afin de ne pas avoir à exécuter le code qui ajoute ou supprime le promptDisplay. Il est généralement dangereux de faire ça car on coupe tout lien avec le code porté par l’héritage, mais dans notre cas on risque rien, car en remontant la chaîne d’héritage on se rend compte que la fonction commitCurrentState que nous venons de redéfinir est la première redéfinition d’une fonction vide.

Si on lance notre code maintenant nous n’obtenons pas encore le résultat voulu

Effectivement, nous avons retiré l’ajout du promptDisplay, nous allons donc gérer cette partie dans le constructeur de notre composant.

public class PromptTextInputSkin extends TextInputSkin
{
	public function PromptTextInputSkin(){
		super();
		promptDisplay = createPromptDisplay();
		this.addChild(promptDisplay);
	}

Maintenant le prompt est affiché continuellement, mais le texte vient se superposer par-dessus.

Mise en place des différents composants

Afin de remédier à ce problème nous allons redéfinir une fonction indispensable des skins, il s’agit de la fonction layoutContents, cette fonction permet la mise en place des éléments de la skin.

// Define gap beetween prompt and text
[Style(name="gap", type="Number", format="Number", inherit="yes")]

override protected function layoutContents(unscaledWidth:Number, unscaledHeight:Number):void
{
	super.layoutContents(unscaledWidth, unscaledHeight);

	if(promptDisplay) {
		var leftMarginText:int = promptDisplay.x + promptDisplay.textWidth + getStyle('gap');
		var rightMarginText:int = getStyle('paddingRight');
		var textDisplaySize:int = hostComponent.width - leftMarginText - rightMarginText;

		//Replace la partie texte pour ne pas chevaucher le prompt
		setElementPosition(textDisplay, leftMarginText , textDisplay.y);
		//Redéfini la taille de la partie texte afin de prendre en compte les nouvelles marges
		setElementSize(textDisplay, textDisplaySize, textDisplay.height);
	}
}

Le gap est un Style ajouté, qui permettra dans notre CSS de définir l’espacement entre le prompt et le texte.

Afin de spécifier la marge qui doit être laissée à gauche du texte, nous calculons les éléments suivants : position x du prompt + taille du texte + le gap.

On récupère aussi la marge à laisser côté droit du texte, cela nous permettra de définir la nouvelle taille du texte.

La taille du texte est donc la taille du composant TextInput auquel on soustrait les marges de droites et de gauche.

On fait ensuite appel aux fonctions setElementPosition et setElementSize afin que le texte ne déborde pas du composant et ne sois plus superposé avec le prompt.

On se rapproche du résultat final, on remarque quand même quelques détails de style manquant :

  • Le prompt n’a pas le format voulu (gras, noir)
  • Le texte n’a pas l’alignement voulu.

Finir avec style

Pour remédier à ce problème nous utilisons donc la dernière méthode qui nous permet de jouer sur les propriétés du composant, il s’agit de la méthode commitProperties.

// Define color of the prompt text
[Style(name="promptColor", type="uint", format="Color", inherit="no")]

// Define font Weigth of the prompt text
[Style(name="promptFontWeight", type="String", format="String", inherit="no")]

override protected function commitProperties():void
{
	super.commitProperties();
	promptDisplay.setStyle('color', getStyle('promptColor'));
	promptDisplay.setStyle('fontWeight', getStyle('promptFontWeight'));
	promptDisplay.setStyle('textAlign', 'left');
}

On ajoute ici deux style pour la mise en forme du prompt, on force par défaut le promptDisplay à gauche sinon il est dépendant de la mise en forme textAlign et dans cet exemple nous n’avons pas prévu un affichage à droite du prompt.
On termine donc par une petite touche de CSS et le tour est joué

skins|PromptTextInputSkin {
	gap : 10px;
	promptColor : black;
	promptFontWeight : bold;
	textAlign : right;
}

Le résultat correspond à nos attentes, voici une base de travail pour ajouter une image comme dans cet exemple développé par nos amis de people in action inclus dans la lib e-skimo.

 

 

Remplis sous: Adobe Air, Skin 4 Commentaires
31mai/110

Flex Tips – Empêcher la saisie d'un retour chariot dans un champ texte

Un petit "snippet" de code qui peut vous être bien utile lorsque vous voulez interdire la saisie d'un caractère retour chariot dans un champ texte (TextArea par exemple).

Mon cas d'utilisation était un écran d'une interface mobile. Celle-ci est réduite en largeur et j'affiche un champ texte sur plusieurs lignes, pour que l'utilisateur voit ce qu'il tape. Ce qu'il doit taper est une URL, et je veux que lorsqu'il appuie sur la touche entrée de son clavier, la saisie soit validée mais que le caractère "\n" lui-même ne soit pas entré.

La propriété "restrict" permettant de donner une expression régulière à valider prend en compte tous les caractère sauf le retour chariot, il vous faut donc une autre solution.

Pour cela, il suffit de s'abonner à l'évènement "textInput" qui peut être stoppé grâce à la méthode preventDefault:

private function textArea_textInput(event:TextEvent):void {
  if (event.text == "\n") {
    event.preventDefault();
  }
}

Avec ce bout de code, vous allez empêcher la saisie mais si l'utilisateur effectue un copier-coller d'un contenu ayant un retour chariot, celui-ci sera accepté. Pour éviter cela, il suffit de s'abonner sur l'évènement "change" et de remplacer les retours chariot éventuels:

private function textArea_change(event:Event):void {
  textArea.text = textArea.text.replace(/\\n|\\r/ig, "");
}
5mai/1112

AIR Mobile – Les composants et le thème Mobile Flex 4.5

L'avantage de pouvoir utiliser les composants Flex par rapport à une application pure AS3 est de simplifier le développement en vous donnant toute une bibliothèque de composants prêts à l'emploi. Certains composants sont de nouveaux composants, d'autres ont simplement une autre "Skin" optimisée pour le rendu mobile (plus gros, système de cache, etc.). Bien sûr, vous pouvez toujours faire vos propres composants mais on va voir ceux qui sortent directement du four. Dans ce billet, on va découvrir ces composants et leurs looks pour vous donner une idée.

Notez que les itemRenderer seront couverts dans un autre billet sur flex-tutorial.

Bouton

Ce n'est pas un nouveau composant, seulement le composant s:Button avec un look différent lorsque vous l'utilisez dans un projet de type Mobile:

buttons

Notez que le composant Spark Button a retrouvé sa propriété "icon" vous permettant d'ajouter un icône directement avec la Skin de base (il fallait faire sa propre Skin auparavant).

26nov/088

Composant Flex – AutoCompletion sur un champ Texte (AutoComplete TextInput)

Pour vos applications, vous aurez peut-être besoin de proposer à l'utilisateur une liste de choix. Par exemple pour proposer une liste de pays dans un formulaire ou une liste de contacts. Pour afficher ces contacts, vous pouvez utiliser une ComboBox qui va créer un menu déroulant contenant tous les éléments de la liste. Si votre liste est importante, vous allez vouloir laisser l'utilisateur filtrer cette liste, par exemple, en rentrant les premières lettres du mot qu'il recherche. Ce type de champ avec auto-complétion (autocomplete) est par exemple utilisé par Google Suggest pour proposer les recherches les plus pertinentes au fur et à mesure de la frappe.Il y a aujourd'hui plusieurs composants Flex qui ont été crées pour faire cette auto-suggestion. En voici 3 qui paraissent les plus pertinents (du moins bon au meilleur)