Flex/ Flex 4.5

Flex 4.5 TextArea auto-scroll e desabilitar scrolls

O TextArea é um componente incrível, além de suportar textos simples (String) ele também suporta o Text Layout Framework, e com essa nova arquitetura Spark a coisa ficou tão fácil que até parece brincadeira de criança.

Recemente alguns e-mails chegaram em minha caixa de entrada com várias perguntas a respeito do auto-scroll do TextArea, uma coisa bastante comum no Flex 3 TextArea é que você tem que programaticamente dar o scroll para baixo via actionscript, já no Flex 4.5 você vai perceber que isso é automático e então você não precisa debulhar o componente e criar um novo apenas para isso.

Por um lado ele traz essa praticidade, por outro ele traz um desavento devido a nova API e métodos distintos, por exemplo, Se você quiser manter o scroll mesmo texto crescendo no topo, você tem que usar o método scrollToRange, que faz o metodo inverso do comportamento natural do Flex 4.5 TextArea.

Por exemplo scroll inverso:

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
			   xmlns:s="library://ns.adobe.com/flex/spark"
			   xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600">
	<fx:Script>
		<![CDATA[
			import spark.events.TextOperationEvent;
 
			protected function meuTexto_changeHandler(event:TextOperationEvent):void
			{
				meuTexto.textDisplay.scrollToRange(0,0);
			}
 
		]]>
	</fx:Script>
	<fx:Declarations>
		<!-- Place non-visual elements (e.g., services, value objects) here -->
	</fx:Declarations>
	<s:TextArea id="meuTexto" x="72" y="81" minWidth="361" minHeight="276" prompt="Cole algum texto aqui" change="meuTexto_changeHandler(event)"/>
</s:Application>

O scrollToRange é acessível apenas pela propriedade textDisplay que é detentora dos textos(simples, não confunda com textFlow) atribuídos ao TextArea. Com essa propriedade você consegue expor mais opções para seu componente como é o caso da propriedade pública maxChars diretamente acessível pelo TextArea.

Abra o código fonte e você vai ver que ele primeiro seta via textDisplay.

 public function set maxChars(value:int):void
    {
        if (textDisplay)
        {
            textDisplay.maxChars = value; // aqui você seta.
            textDisplayProperties = BitFlagUtil.update(
                uint(textDisplayProperties), MAX_CHARS_PROPERTY_FLAG, true);
        }
        else
        {
            textDisplayProperties.maxChars = value;
        }
 
        // Generate an UPDATE_COMPLETE event.
        invalidateProperties();
    }

E com a brincadeira de Skins, você pode fazer muito mais, por exemplo veja esse Skin que criei para meu TextArea.

<?xml version="1.0" encoding="utf-8"?>
 
<!--
 
    ADOBE SYSTEMS INCORPORATED
    Copyright 2008 Adobe Systems Incorporated
    All Rights Reserved.
 
    NOTICE: Adobe permits you to use, modify, and distribute this file
    in accordance with the terms of the license agreement accompanying it.
 
-->
 
<!--- The default skin class for Spark TextArea component.
 
     @see spark.components.TextArea
 
      @langversion 3.0
      @playerversion Flash 10
      @playerversion AIR 1.5
      @productversion Flex 4
-->
<s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark"
    xmlns:fb="http://ns.adobe.com/flashbuilder/2009"
    alpha.disabledStates="0.5" blendMode="normal">
 
    <fx:Metadata>
    <![CDATA[
        /**
         * @copy spark.skins.spark.ApplicationSkin#hostComponent
         */
        [HostComponent("spark.components.TextArea")]
    ]]>
    </fx:Metadata>
 
    <fx:Script fb:purpose="styling">
        <![CDATA[
        import mx.core.FlexVersion;
 
        private var lineBreakChanged:Boolean;
        private var paddingChanged:Boolean;
        private var verticalAlignChanged:Boolean;
 
        /* Define the skin elements that should not be colorized.
           For text area, the skin itself is colorized but the individual parts are not as well
           as the border since it uses the borderColor style. */
        static private const exclusions:Array = ["background", "scroller", "promptDisplay", "border"];
 
        /* exclusions before Flex 4.5 for backwards-compatibility purposes */
        static private const exclusions_4_0:Array = ["background", "scroller", "promptDisplay"];
 
        /**
         * @private
         */
        override public function get colorizeExclusions():Array
        {
            // Since border is styleable via borderColor, no need to allow chromeColor to affect
            // the border.  This is wrapped in a compatibility flag since this change was added
            // in Flex 4.5
            if (FlexVersion.compatibilityVersion < FlexVersion.VERSION_4_5)
            {
                return exclusions_4_0;
            }
 
            return exclusions;
        }
 
        /* Define the content fill items that should be colored by the "contentBackgroundColor" style. */
        static private const contentFill:Array = ["bgFill"];
 
        /**
         *  @private
         */
        override public function get contentItems():Array {return contentFill};
 
        /**
         *  @private
         */
        override protected function commitProperties():void
        {
            super.commitProperties();
 
            if (lineBreakChanged)
            {
                updateStringStyle("lineBreak");
                lineBreakChanged = false;
            }
            if (paddingChanged)
            {
                updatePadding();
                paddingChanged = false;
            }
            if (verticalAlignChanged)
            {
                updateStringStyle("verticalAlign");
                verticalAlignChanged = false;
            }
        }
 
        /**
         * @private
         */
        override protected function initializationComplete():void
        {
            useChromeColor = true;
            super.initializationComplete();
        }
 
        /**
         *  @private
         */
        override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
        {
            if (getStyle("borderVisible") == true)
            {
                border.visible = true;
                shadow.visible = true;
                background.left = background.top = background.right = background.bottom = 1;
                textDisplay.left = textDisplay.top = textDisplay.right = textDisplay.bottom = 1;
                if (promptDisplay)
                {
                    promptDisplay.setLayoutBoundsSize(unscaledWidth - 2, unscaledHeight - 2);
                    promptDisplay.setLayoutBoundsPosition(1, 1);
                }
            }
            else
            {
                border.visible = false;
                shadow.visible = false;
                background.left = background.top = background.right = background.bottom = 0;
                if (promptDisplay)
                {
                    promptDisplay.setLayoutBoundsSize(unscaledWidth - 1, unscaledHeight - 1);
                    promptDisplay.setLayoutBoundsPosition(1, 1);
                }
            }
 
            borderStroke.color = getStyle("borderColor");
            borderStroke.alpha = getStyle("borderAlpha");
 
            super.updateDisplayList(unscaledWidth, unscaledHeight);
        }
 
        /**
         *  @private
         */
        private function updatePadding():void
        {
            if (!textDisplay)
                return;
 
            // Push padding styles into the textDisplay
            var padding:Number;
 
            padding = getStyle("paddingLeft");
            if (textDisplay.getStyle("paddingLeft") != padding)
                textDisplay.setStyle("paddingLeft", padding);
 
            padding = getStyle("paddingTop");
            if (textDisplay.getStyle("paddingTop") != padding)
                textDisplay.setStyle("paddingTop", padding);
 
            padding = getStyle("paddingRight");
            if (textDisplay.getStyle("paddingRight") != padding)
                textDisplay.setStyle("paddingRight", padding);
 
            padding = getStyle("paddingBottom");
            if (textDisplay.getStyle("paddingBottom") != padding)
                textDisplay.setStyle("paddingBottom", padding);
 
            if (!promptDisplay)
                return;
 
            padding = getStyle("paddingLeft");
            if (promptDisplay.getStyle("paddingLeft") != padding)
                promptDisplay.setStyle("paddingLeft", padding);
 
            padding = getStyle("paddingTop");
            if (promptDisplay.getStyle("paddingTop") != padding)
                promptDisplay.setStyle("paddingTop", padding);
 
            padding = getStyle("paddingRight");
            if (promptDisplay.getStyle("paddingRight") != padding)
                promptDisplay.setStyle("paddingRight", padding);
 
            padding = getStyle("paddingBottom");
            if (promptDisplay.getStyle("paddingBottom") != padding)
                promptDisplay.setStyle("paddingBottom", padding);
        }
 
        /**
         *  @private
         */
        private function updateStringStyle(styleName:String):void
        {
            if (!textDisplay)
                return;
 
            // Push style into the textDisplay
            var style:String;
 
            style = getStyle(styleName);
            if (textDisplay.getStyle(styleName) != style)
                textDisplay.setStyle(styleName, style);
 
            if (!promptDisplay)
                return;
 
            // Push style into the promptDisplay
            style = getStyle(styleName);
            if (promptDisplay.getStyle(styleName) != style)
                promptDisplay.setStyle(styleName, style);
        }
 
        /**
         *  @private
         */
        override public function styleChanged(styleProp:String):void
        {
            var allStyles:Boolean = !styleProp || styleProp == "styleName";
 
            super.styleChanged(styleProp);
 
            if (allStyles || styleProp.indexOf("lineBreak") == 0)
            {
                lineBreakChanged = true;
                invalidateProperties();
            }
            if (allStyles || styleProp.indexOf("padding") == 0)
            {
                paddingChanged = true;
                invalidateProperties();
            }
            if (allStyles || styleProp.indexOf("verticalAlign") == 0)
            {
                verticalAlignChanged = true;
                invalidateProperties();
            }
        }
 
			protected function changeSelectHandler(event:Event):void
			{
				// TODO Auto-generated method stub
				if(allText.selected)
					textDisplay.selectAll();
				else
					textDisplay.selectRange(textDisplay.text.length,textDisplay.text.length);
 
			}
 
		]]>
    </fx:Script>
 
    <fx:Script>
        <![CDATA[
        /**
         * @private
         */
        private static const focusExclusions:Array = ["textDisplay"];
 
        /**
         *  @private
         */
        override public function get focusSkinExclusions():Array { return focusExclusions;};
        ]]>
    </fx:Script>
 
    <s:states>
        <s:State name="normal"/>
        <s:State name="disabled" stateGroups="disabledStates"/>
        <s:State name="normalWithPrompt"/>
        <s:State name="disabledWithPrompt" stateGroups="disabledStates"/>
    </s:states>
 
 
    <!-- border -->
    <!--- @private -->
    <s:Rect id="border" left="0" right="0" top="0" bottom="0">
        <s:stroke>
            <!--- @private -->
            <s:SolidColorStroke id="borderStroke" weight="1"/>
        </s:stroke>
    </s:Rect>
 
    <!-- fill -->
    <!--- Defines the appearance of the TextArea component's background. -->
    <s:Rect id="background" left="1" right="1" top="1" bottom="1">
        <s:fill>
            <!--- @private Defines the background fill color. -->
            <s:SolidColor id="bgFill" color="0xFFFFFF" />
        </s:fill>
    </s:Rect>
 
    <!-- shadow -->
    <!--- @private -->
    <s:Rect id="shadow" left="1" top="1" right="1" height="1">
        <s:fill>
            <s:SolidColor color="0x000000" alpha="0.12" />
        </s:fill>
    </s:Rect>
 
    <!--- Defines the scroller that is used to scroll the TextArea control. -->
    <s:Scroller id="scroller" left="0" top="20" right="0" bottom="0" minViewportInset="1" measuredSizeIncludesScrollBars="false" hasFocusableChildren="false">
        <!--- @copy spark.components.supportClasses.SkinnableTextBase#textDisplay -->
        <s:RichEditableText id="textDisplay" heightInLines="10" widthInChars="15" />
    </s:Scroller>
 
    <!--- Defines the Label that is used for prompt text. The includeInLayout property is false so the prompt text does not affect measurement. -->
    <s:Label id="promptDisplay"
                mouseEnabled="false" mouseChildren="false"
                includeIn="normalWithPrompt,disabledWithPrompt"
                includeInLayout="false"
                />
	<!-- grupo header -->
	<s:Rect left="0" right="0" top="0" height="20">
		<s:fill>
			<s:SolidColor color="#f4f4f4"/>
		</s:fill>
	</s:Rect>
	<s:Group left="0" right="0" top="0">
		<s:layout>
			<s:HorizontalLayout verticalAlign="middle"/>
		</s:layout>
		<s:Label text="Posição atual da seleção: {textDisplay.selectionActivePosition}"/>
		<s:CheckBox includeIn="normal" id="allText" label="Selecionar tudo" change="changeSelectHandler(event)"/>
	</s:Group>
</s:SparkSkin>

Basta aplicar ele em qualquer textArea que ele vai mostrar a posição atual do cursor na palavra e terá um checkBox perguntando se você quer selecionar todo o texto ou não.

Para aplicar é simples:

	<s:TextArea skinClass="MyTextAreaSkin" id="meuTexto" x="72" y="81" minWidth="361" minHeight="276"
				prompt="Cole algum texto aqui" change="meuTexto_changeHandler(event)"/>

Chamei meu Skin de MyTextAreaSkin, fácil não? Começe agora mesmo a dedilhar cada nova classe do SDK, você vai ficar maravilhado com as simplicidades que ele traz e a facilidade de expandir.

Flash Builder 4.5/ Flex/ Flex 3 para Flex 4/ Flex 4.5

Flex 3 para Flex 4.5 – Datagrid

Wow, que mudança; Imagine você acostumado com o Datagrid do Flex 3.x e de repente você se depara com o novo Datagrid do Flex 4.5.1. Se você tem pleno conhecimento do Flex, você terá um esforço médio de 10%, agora se você pega o Flex de vez em quando, perceberá de início que mudou 50%, que sá 100%.

Veja o diagrama do novo Datagrid.

datagrid-spec-diagram

Algumas mudanças bem acentuadas estão:

  • A classe Datagrid não é uma subclass do List ou ListBase
  • Todos os itens criados para o Datagrid são declarativos, ou seja você não tem aquela chatisse de sobrescrever vários métodos como era necessário no Flex 3.x
  • itemClick, DropEnable, DragEnable, AllowMultiSelection entre outras propriedades não existem mais, você tem que fazer na unha via Actionscript 3.0
  • Scrollbars eram parte integrante da estrutura de Halo, ou seja ele variava de acordo com o Height de cada item e a posição sempre era baseada nisso, no novo Datagrid a posição sempre é alterada quando há scrolling, você tem proveito do Smooth Scrolling por exemplo.
  • Não há suporte a estilos como era feito no Datagrid do Flex 3, nesse caso eles forçam você a adotar mesmo Skins para os itens, no caso se você quiser aplicar estilos, será necessário usar o styleName onde você quer aplicar as mudanças.
  • Tooltips nos dados agora são dataTips, a grande vantagem disso é que você pode usar igual aos MX Charts, showDatatips é uma propriedade que você pode exibir todos.
  • Leia todas as mudanças aqui na especificação do novo componente.

Agora sabendo dessas pequenas mudanças, vamos ver alguns exemplos práticos que no dia-a-dia você vai lutar contra.

Datagrid Simples e preenchido

 
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
			   xmlns:s="library://ns.adobe.com/flex/spark"
			   xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600">
	<fx:Declarations>
		<!-- Place non-visual elements (e.g., services, value objects) here -->
	</fx:Declarations>
	<s:DataGrid showDataTips="true" x="312" y="108" requestedRowCount="4">
		<s:columns>
			<s:ArrayList>
				<s:GridColumn dataField="dataField1" headerText="Column 1"></s:GridColumn>
				<s:GridColumn dataField="dataField2" headerText="Column 2"></s:GridColumn>
				<s:GridColumn dataField="dataField3" headerText="Column 3"></s:GridColumn>
			</s:ArrayList>
		</s:columns>
		<s:typicalItem>
			<fx:Object dataField1="Sample Data" dataField2="Sample Data" dataField3="Sample Data"></fx:Object>
		</s:typicalItem>
		<s:ArrayList>
			<fx:Object dataField1="data1" dataField2="data1" dataField3="data1"></fx:Object>
			<fx:Object dataField1="data2" dataField2="data2" dataField3="data2"></fx:Object>
			<fx:Object dataField1="data3" dataField2="data3" dataField3="data3"></fx:Object>
			<fx:Object dataField1="data4" dataField2="data4" dataField3="data4"></fx:Object>
		</s:ArrayList>
	</s:DataGrid>
</s:Application>

Drag and Drop desabilitados por padrão, implementados manualmente.

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
			   xmlns:s="library://ns.adobe.com/flex/spark"
			   xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600" creationComplete="initApp(event)">
	<fx:Declarations>
		<!-- Place non-visual elements (e.g., services, value objects) here -->
	</fx:Declarations>
	<fx:Script>
		<![CDATA[
			import mx.events.FlexEvent;
			import mx.graphics.ImageSnapshot;
 
			import spark.components.Grid;
			import spark.components.gridClasses.CellPosition;
			import spark.events.GridEvent;
			import spark.primitives.BitmapImage;
			import spark.primitives.Rect;
 
 
			private var item:Object;
			private var gost:BitmapImage;
 
			protected function initApp(event:FlexEvent):void
			{
				tabela.addEventListener(GridEvent.GRID_MOUSE_DOWN,dragItens,false,1,true);
				tabela2.addEventListener(GridEvent.GRID_MOUSE_UP,releaseItem,false,1,true);
			}
 
			protected function dragItens(event:GridEvent):void
			{
				// pega o item selecionado e arrasta
				item = tabela.selectedItem;
 
				// cria um fantasma do item selecionado
				var posX:Number = tabela.mouseX;
				var posY:Number = tabela.mouseY;
 
				gost = new BitmapImage();
				//var imageBitmapData:BitmapData = ImageSnapshot.captureBitmapData(event.currentTarget.grid,null,null,null,
				//	new Rectangle(tabela.x,event.currentTarget.rowHeight,tabela.width,event.currentTarget.rowHeight));
				var imageBitmapData:BitmapData = ImageSnapshot.captureBitmapData(event.currentTarget.grid,null,null,null,
					new Rectangle(posX,posY,tabela.width,26));
				gost.source = new Bitmap(imageBitmapData);
				gost.x = mouseX - 50;
				gost.y = mouseY - 50;
				this.addElement(gost);
				stage.addEventListener(MouseEvent.MOUSE_MOVE,moveGost,false,3,true);
				stage.addEventListener(MouseEvent.MOUSE_UP,removeGost,false,4,true);
 
			}
			protected function moveGost(e:MouseEvent):void
			{
				if(gost != null){
				gost.x = mouseX -50;
				gost.y = mouseY -50;
				}
			}
			protected function removeGost(event:Event):void
			{
				// TODO Auto-generated method stub
				if(gost !=null)
				{
					this.removeElement(gost);
					gost = null;
				}
			}
 
			protected function releaseItem(event:GridEvent):void
			{
 
					tabela2.dataProvider.addItem(item);
 
					item = null;
			}
 
 
		]]>
	</fx:Script>
	<s:DataGrid id="tabela" x="44" y="99" width="348" height="286" requestedRowCount="4"
				showDataTips="true">
		<s:columns>
			<s:ArrayList>
				<s:GridColumn dataField="dataField1" headerText="Column 1"></s:GridColumn>
				<s:GridColumn dataField="dataField2" headerText="Column 2"></s:GridColumn>
				<s:GridColumn dataField="dataField3" headerText="Column 3"></s:GridColumn>
			</s:ArrayList>
		</s:columns>
		<s:typicalItem>
			<fx:Object dataField1="Sample Data" dataField2="Sample Data" dataField3="Sample Data"></fx:Object>
		</s:typicalItem>
		<s:ArrayList>
			<fx:Object dataField1="data1" dataField2="data1" dataField3="data1"></fx:Object>
			<fx:Object dataField1="data2" dataField2="data2" dataField3="data2"></fx:Object>
			<fx:Object dataField1="data3" dataField2="data3" dataField3="data3"></fx:Object>
			<fx:Object dataField1="data4" dataField2="data4" dataField3="data4"></fx:Object>
		</s:ArrayList>
	</s:DataGrid>
	<s:DataGrid id="tabela2" x="433" y="99" width="383" height="286" requestedRowCount="4">
		<s:columns>
			<s:ArrayList>
				<s:GridColumn dataField="dataField1" headerText="Column 1"></s:GridColumn>
				<s:GridColumn dataField="dataField2" headerText="Column 2"></s:GridColumn>
				<s:GridColumn dataField="dataField3" headerText="Column 3"></s:GridColumn>
			</s:ArrayList>
		</s:columns>
		<s:typicalItem>
			<fx:Object dataField1="Sample Data" dataField2="Sample Data" dataField3="Sample Data"></fx:Object>
		</s:typicalItem>
		<s:ArrayList>
			<fx:Object dataField1="data1" dataField2="data1" dataField3="data1"></fx:Object>
			<fx:Object dataField1="data2" dataField2="data2" dataField3="data2"></fx:Object>
			<fx:Object dataField1="data3" dataField2="data3" dataField3="data3"></fx:Object>
			<fx:Object dataField1="data4" dataField2="data4" dataField3="data4"></fx:Object>
		</s:ArrayList>
	</s:DataGrid>
</s:Application>

Existe um mar de possibilidades, provavelmente eu volte a falar mais do DataGrid do Flex 4.5 por aqui. Fique ligado nas mudanças.

AIR 2.7/ AIR Mobile/ Android/ Flash Builder/ Flash Builder 4.5/ Flex/ Flex Mobile Framework

Flex 4.5.1 SDK e Flash Builder 4.5.1 com suporte a iOS

E viva! o Flash Builder 4.5.1 agora dá suporte a publicar sua aplicação Flex para plataforma iOS. Embora ela tenha lançado esse suporte o Flash Builder 4.1 já havia suporte para projetos com Actionscript 3.0 puro.

Esse novo lançamento vem fomentar mais ainda o mercado e ajudar a entregar aplicações ao tablet da Apple e também ao iPhones. Antes desse lançamento já era possível fazer via linha de comando com o último SDK 4.5. Porém é um baita rodeio para você fazer compliar.

Com os wizards do Flash Builder 4.5.1 para ios, a coisa ficou bem mais fácil. Para quem já tem o Flash 4.5 registrado baixe gratuitamente aqui o update.

Dica importante, para quem está publicando apps em Flex para iOS, não usem o AIR 2.6 SDK que é o padrão dessa versão. Leiam esse documento para que vocês possam utilizar o AIR 2.7 que está 4x mais rápido do que a atual versão suportada no SDK.

Outra dica para quem está publicando para o Blackberry Playbook, leiam esse release no Blog da RIM.

Quem é ligado como eu nos released notes sobre bugs existentes e já conhecidos, leia aqui. Nele você também encontra informações como usar o Flash Builder no Linux.

AIR 2.7/ AIR Mobile/ Dicas/ Notícias

Adobe AIR 2.7 lançado e cheio das novidades

Informalmente falando, estou bem animado com as novidades do AIR tanto para Android quanto para iOS, a performance está incrivelmente melhor no iOS, bem que o Arno, gerente de engenharia do AIR falou no Flashcamp Brasil em sua palestra.

Recompilei 2 apps (jogos) que estavamos fazendo com o novo AIR 2.7 e está incrivelmente melhor, nada se compara a um código feito nativamente, mais está muito bacana.

E uma das funções novas que eu mais gostei, foi a possibilidade de mudar o AIR para o SD do smartphone, afinal ele tem 17mb que usa da memória interna e isso é um pé no saco, já que o Android usa dessa memória para rodar aplicativos múltiplos.

Adorei as novidades, você pode conferir todas aqui.

Baixar para Android, já está disponível no Android Market, se você tem aplicativo feito em iOS com AIR 2.5 ou 2.6. Recompile com o novo SDK, você vai me agradecer pelo resto da sua vida por essa dica, roda muito mais rápido.

Para Desktop só seguir aqui.

Flash Builder 4.5/ Flex/ Flex 4.5

Corretor ortográfico em aplicações Flash/Flex/AIR

Já pensou em ter uma aplicação que possa corrigir erros ortográficos em alguns aplicativos, por exemplo, aplicações de edição de textos públicos, licitatórios, organizadores de documentos virtuais, edição de textos, em fim uma gama de aplicações são pertinentes ao assunto. E A Adobe tem há algum tempo uma biblioteca gratuita que você pode usar para adicionar essa funcionabilidade ao seu aplicativo.

A Squiggly, além de gratuita ela se baseia em dicionário público e open-source que é bastante utilizado nos navegadores Chrome, Firefox e a suite de office open-source Open-Office. Tem alguns bugs conhecidos, mais nada que lhe impeça de criar essa função em seu aplicativo.

E cá entre nós, praticamente 50% dos sistemas não tem um corretor ortográfico em campos como comentários adicionais, preenchimento de dados específicos como descrição de produtos, e acaba afetando, ou vai dizer que todo o texto que seu sistema controla é feito pelo Word?

Vamos lá fazer um exemplo.

Passo 1 – Criar um projeto
Passo 2 – Baixar o SWC do Squiggly.
Passo 3 – Adicionar o SWC’s do Squiggly no diretório lib de seu projeto. Os SWCs você vai encontrar direto na pasta libs do arquivo .zip que você baixou. Veja como ficou o meu abaixo.
squiggly

Agora, o resto é fácil. Veja um exemplo abaixo que criei. Lembre-se estou usando o Flex 4.5, funciona com Flash, AIR 2.0+ e em projetos Actionscript 3.0 puro. No .zip que você baixar vai encontrar vários exemplos.

Publicador

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
			   xmlns:s="library://ns.adobe.com/flex/spark"
			   xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600">
	<fx:Style>
		@namespace s "library://ns.adobe.com/flex/spark";
		s|Form s|FormItem
		{
			skinClass: ClassReference("spark.skins.spark.StackedFormItemSkin");
		}
		s|Form s|FormHeading
		{
			skinClass: ClassReference("spark.skins.spark.StackedFormHeadingSkin");
		}
	</fx:Style>
	<fx:Declarations>
		<!-- Place non-visual elements (e.g., services, value objects) here -->
	</fx:Declarations>
 
	<s:Form x="170" y="45" width="487" height="486">
			<s:FormItem label="Título do post:" width="100%">
				<s:TextInput id="campoTitulo" width="100%"/>
			</s:FormItem>
			<s:FormItem label="Post:" width="100%">
				<s:TextArea id="campoCorpoTexto" width="100%" height="300">
 
				</s:TextArea>
			</s:FormItem>
			<s:Button width="135" height="35" label="Publicar" fontWeight="bold"/>
	</s:Form>
</s:Application>

Ok, até ai tudo bem, o problema agora é o seguinte, por padrão o Squiggly trás apenas o idioma en_US, para o corretor, o que nos faz pesquisar no Google e tentar achar outros idiomas, já que é gratuito e eu mencionei OpenOffice, então facilmente eu consigo esse dicionário em pt_BR. Ah! achei.

Com o dicionário em mãos, eu vou criar a seguinte estrutura em meu projeto.

squiggly_pt_br

Veja que tem a estrutura en_US, pt_BR dentro da pasta dictionaries, essas pastas por padrão estão dentro do pacote que você baixou do squiggly. Você vai encontrar ela (en_US) dentro da pasta src.

Agora o que você precisa fazer é mapear essa nova biblioteca que você adicionou(pt_BR) ao AdobeSpellingConfig.xml que está no projeto, ele tem o atual código.

<?xml version="1.0" encoding='UTF-8'?>
<spellingConfig>
  <languageResource language="English" languageCode="en_US" ruleFile="dictionaries/en_US/en_US.aff" dictionaryFile="dictionaries/en_US/en_US.dic"/>
</spellingConfig>

Troque por essa:

<?xml version="1.0" encoding='UTF-8'?>
<spellingConfig>
  <languageResource language="English" languageCode="en_US" ruleFile="dictionaries/en_US/en_US.aff" dictionaryFile="dictionaries/en_US/en_US.dic"/>
  <languageResource language="Português Brasil" languageCode="pt_BR" ruleFile="dictionaries/pt_BR/pt_BR.aff" dictionaryFile="dictionaries/pt_BR/pt_BR.dic"/>
</spellingConfig>

Adicione quantos idiomas você quiser. Agora voltamos ao código de nossa aplicação.

Eu peguei o código e apliquei as dependências do Squiggly. Então, veja como ficou.

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
			   xmlns:s="library://ns.adobe.com/flex/spark"
			   xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600" creationComplete="startMeuCorretor(event)">
	<fx:Style>
		@namespace s "library://ns.adobe.com/flex/spark";
		s|Form s|FormItem
		{
			skinClass: ClassReference("spark.skins.spark.StackedFormItemSkin");
		}
		s|Form s|FormHeading
		{
			skinClass: ClassReference("spark.skins.spark.StackedFormHeadingSkin");
		}
	</fx:Style>
	<fx:Script>
		<![CDATA[
			import com.adobe.linguistics.spelling.SpellUI;
			import com.adobe.linguistics.spelling.framework.ResourceTable;
			import com.adobe.linguistics.spelling.framework.SpellingConfiguration;
 
			import mx.events.FlexEvent;
 
			protected function startMeuCorretor(event:FlexEvent):void
			{
				// TODO Auto-generated method stub
				var dicionarios:ResourceTable = new ResourceTable();
			//opcional	dicionarios.setResource("en_US", {rule:"dicionaries/en_US/en_US.aff", dict:"dicionaries/en_US/en_US.dic"});
				dicionarios.setResource("pt_BR", {rule:"dicionaries/pt_BR/pt_BR.aff", dict:"dicionaries/pt_BR/pt_BR.dic"});
				SpellingConfiguration.resourceTable = dicionarios;
 
			}
 
		]]>
	</fx:Script>
	<fx:Declarations>
		<!-- Place non-visual elements (e.g., services, value objects) here -->
	</fx:Declarations>
 
	<s:Form x="170" y="45" width="487" height="486">
			<s:FormItem label="Título do post:" width="100%">
				<s:TextInput id="campoTitulo" width="100%" creationComplete="SpellUI.enableSpelling(campoTitulo, 'pt_BR');"/>
			</s:FormItem>
			<s:FormItem label="Post:" width="100%">
				<s:TextArea id="campoCorpoTexto" width="100%" height="300" creationComplete="SpellUI.enableSpelling(campoCorpoTexto,'pt_BR')">
 
				</s:TextArea>
			</s:FormItem>
			<s:Button width="135" height="35" label="Publicar" fontWeight="bold"/>
	</s:Form>
</s:Application>

Resultado final:

squiggly_post

Com isso, basta publicar sua aplicação com todas as dependências de dicionários e arquivos e sua aplicação estará pronta para corrigir os assassinos de palavras portuguesas.

Aproveita, é simples, legal de implementar. Até o próximo post.

Eventos/ Flex/ Flex Mania/ Notícias

Flex Mania 2011 anunciado, eu vou e você?

Pelo terceiro ano consecutivo o Flex Mania, acontece, on-line diretamente na tela de seu computador, não tem a chatisse de filas, tickets, credenciamentos; Ah e nem tem também o pagamento do ticket, o evento é gratuito, 0800, di gratis, como você gostar de chamar.

Vou palestrar sobre Campanhas publicitárias em dispositivos móveis com a tecnologia Flash.

É um evento fenomenal, esse ano juntamos vários tópicos não só relacionados a Flex, mais em si a plataforma geral do Flash, como vocês sabem a Adobe tem trabalhado muito para entregar em suas soluções portabilidade em várias telas e até agora ela tem feito um bom trabalho, esse ano temos várias palestras sobre esse assunto.

Teremos convidados especiais com o evangelista técnico da Adobe Ryan Stewart falando sobre o desenvolvimento para múltiplas telas.

Ao todo são 30 palestrantes, e essa lista pode aumentar, tem alguns palestrantes que não confirmaram ainda então fica ligado na Agenda. Chame os amigos, colegas de trabalho, fale com seu chefe para colocar um telão na hora das palestras favoritas que fizerem sentido para o negócio deles.

Eu estou muito animado para esse ano. Vai de 7 de julho (quinta-feira) até 10 de julho(domingo de manhã), com diversos sorteios.

Esse ano temos o oferecimento principal da BlackBerry e Adobe, nossos parceiros fundamentais para tornar um evento grande como esse gratuito para todos. Sem eles estariamos fritos. Obrigado também a PowerFlasher que está novamente nos patrocinando, O’Reilly e a Element River.

Uma das novidades esse ano é que também teremos transmissão ao vivo em Telão nas instalações da DClick no Rio de Janeiro, Alô cariocas, se vocês querem fazer networking durante o evento terá uma recepção para isso. Colocaremos mais detalhes sobre essas transmissões na próxima semana no site.

Leitores, twittem o que quiser acompanhado da hashtag #flexmania , propagem para seus amigos no Facebook, Orkut, Twitter. É um evento de vocês.

Obrigado a RIACycle por estar mais um ano organizando o evento, tem sido uma empresa muito parceira.

AIR 2.0/ Dicas/ Flash/ Flash Player

Flash é uma pequena parte de nossa empresa,afirma Shantanu Narayen, CEO da Adobe

Seria esse um recado para os próximos 5 anos que o Flash Player e todo o ecosistema da plataforma Flash irá signitivamente diminuir no cenário mundial e nos investimentos da Adobe para a plataforma, e acabar adotando o HTML5 como padrão?

Assista o video do Shantanu Narayen,CEO da Adobe para o D9.

O entrevistador foi honesto e duro com as perguntas, mesmo assim treinado como o Shantanu Narayen é, consegiu escapar e deixar mais complicado para desenvolvedores e usuários finais qual seria o formato para daqui à 5 ou 10 anos.