AIR 2.7/ Flex/ Flex 4.5/ Flex Mobile Framework

Criando seu primeiro aplicativo Flex 4.5 Mobile para smartphones Android parte (2 de 3)

Caso você tenha chegado direto nessa matéria, ela é uma série de 3 partes, essa é a segunda. Se quiser ler do começo, clique aqui.

A estrutura de uma aplicação Android

Uma aplicação Android é como um arquivo .zip, de fato sua extensão .apk é um pacote com a mesma estrutura de um arquivo .zip, onde tem todos os elementos necessários para serem identificados no sistema operacional e assim sua aplicação existir e ter funcionabilidade.

Então, assumindo a premissa que um arquivo .apk seja uma aplicação Android, sua estrutura parte de 3 pilares básicos.

  • Código fonte escrito em Java e usando API do Android SDK
  • Estrutura de organização do projeto
  • Arquivos de mídia

filestructure

Com essa estrutura simplificada você consegue entender facilmente onde vai caber o arquivo de .swf que é embarcado dentro de seu pacote .apk, Na pasta de arquivos de mídia.

Essa pasta guarda o swf compilado com o Flex Framework e as suas classes em um único SWF, evitando assim os preloads, ou erros de fuga que possam ocorrer durante o processo de uso da app, garantindo não só a solidez de uma aplicação flex mobile como sua portabilidade entre diferentes telas e requisitos de sistema Android.

flex_apk_estrutura

Na imagem acima, você pode ver que o time do Flex conseguiu adotar o padrão “assets”, amplamente usado por apps RIA. Vai dizer que você nunca colocou seus ícones dentro desse diretório? A pasta assets substitui naturalmente a pasta /res que guarda esses recursos.

Já que você viu a estrutura de onde vão as coisas, que tal se aprofundar agora no arquivo de maior importância para a estrutura de um app Android?

O arquivo AndroidManifest.xml é a espinha dorsal que faz com que um App seja um App, é o mesmo que sua coluna vertebral, embora você só lembre dela quando está com dores nas costas, a coluna vertebral nos ajuda a definir nossas capacidades musculares, andar hereto e também ter dores 😀

Em fim, o arquivo AndroidManifest.xml ele é uma espécie de coluna vertebral + nervos especiais que definem funções do que sua aplicação mobile vai acessar, requisitar, armazenar e interagir.

Tudo que você faz no AndroidManifest.xml é mapear acessos, requisições e o mais importante permissões, tudo a base de tag de XML. E uma das coisas bem fantásticas disso tudo é que o pessoal da Adobe fez isso de uma forma bem legal, deixando apenas agente se preocupar com os acessos, o que sua App vai acesssar, como GPS, Acelerometro, cartão de memória, Camera e por ai vai. O resto eles cuidam para gente.

Então você sabendo com o que você vai lhe dar, é ultra simples encarar o desafio, veja aqui as permissões existentes no Android, onde nem todas são acessíveis pelo Adobe AIR, algumas apenas são possíveis de acessar por padrão, dentre elas:

air_permissions_by_default

Ufa, chega de explicações, então está preparado para começar a criar seu primeiro projeto Flex Mobile no Flash Builder 4.5.1 ? Vamos lá.

Para criar um novo projeto é simples, existem 3 maneiras:

  • CTRL+N Cria um novo projeto pelo Wizard escolhendo a categoria Flex e depois Flex Mobile Project
  • Vá ao menu File -> New -> Flex Mobile Project
  • Ou usando o Navigator do Flash Builder com o botão direito File -> New -> Flex Mobile Project

De todas as opções, a mais rápida e que praticamente desenvolvedores usam é a terceira, por que economiza tempo na criação e atalhos.

new_flexmobile_project

Lembre-se de setar o SDK que você fez o overlay para a versão Flex 4.5.1 SDK com o AIR 2.7, é super simples de fazer isso, basta clicar na opção Configure SDKs e adicionar o diretório onde você tem o SDK com overlay.

Quando você dá um nome ao projeto, ele particularmente vira o nome da App que você está publicando para o Android Market, então dê nomes simples sem acentos para que você consiga alcançar não só a Android Market Brasileira mais a mundial.

A idéia do nome para App.

Meu aplicativo será um pesquisador de tags do twitter, onde eu vou analisar em diferentes intervalos e tags o que anda rolando na rede social, vou chamar ele de TagsMonitor.

Dado o nome da App de TagsMonitor, eu vou clicar em Next.

config_flexmobile_project

Essa próxima tela é a essência da configuração de sua App.Para não deixar de explicar cada passo, separei por tópicos para você não perder o raciocínio.

Escolhendo a plataforma de publicação

target_platforms

Com configurações extras e exatas você consegue fazer para as outras. Como agente só vai fazer para Android deixo apenas marcado Android.

Escolhendo o template para a aplicação

Existem 3 tipos de aplicação Flex Mobile que você pode fazer, esses templates definem o comportamento de como ela apresenta para o usuário final, os tipos são:
Blank – Uma tela branca onde você tem liberdade de fazer o que quiser, semelhante ao que o Flash também proporciona.
View-Base – Uma tela com um sistema de navegação para N Views(telas). Semelhante ao ViewStack do Flex 2/3.
Tabbed – Que é como o antigo TabNavigator do Flex 2/3 e semelhante ao View-Base, a diferença é que você terá abas prontas para navegar.

view_base_app

Essas diferenças são aplicadas em variados tipos de aplicações e em qual o propósito de sua aplicação. O template mais comum que usaremos é o View-Base. Marque essa opção e pulamos para o próximo tópico.

Permissões acessadas

permissions_config

Como você sabe que para consultar a internet do seu aplicativo dentro de um dispositivo Android você precisa permissões, o Flash Builder por padrão já entende isso e deixa marcado já para você. Se você quiser acessar os outros recursos basta marcar aquele que você deseja. Próximo passo.

Densidade dos dispositivos

Cada fabricante tem seu próprio formato de densidade, até mesmo usando o mesmo OS como é o Android. Uma soma geral de densidades e tipos de telas você pode achar aqui. Que é a referência básica que o Android dispõe baseado em estatísticas coletadas.

google_densidades

A coisa mais legal do Google é que eles atualizam constantemente essas densidades e tamanhos de telas;Felizmente grande parte dos 550mil dispositivos ativados diariamente são normais, tanto no tamanho da tela quanto em sua densidade, que pode variar pouco entre um fabricante e outro. Até por que existe o mundo dos tablets Android e você pode considerar também a criação para ele.

No geral a média é de 240dpi. O que já facilita para gente, que é basicamente o padrão de mercado consideramos assim.

density_config

As outras partes, acredito eu que você vai deduzir que sejam Auto-reorientação que por padrão vem marcado, isso faz sua app ficar responsiva em trabalhar tanto com o device na horizontal ou na vertical.
FullScreen marcando essa opção ele vai esconder a parte do relógio e status, rodando sempre em primeiro plano e deixando o resto da interface gráfica do sistema em segundo plano.
E a última opção que vem é auto escalonar sua aplicação para os padrões de DPI, a Adobe acredita que 160dpi está ótimo, eu discordo dessa abordagem e considero mais padrão 240dpi do que os 160dpi padrão. Seja esperto e marque essa opção e mude de 160dpi para 240dpi.

Clique em Finish. E seu projeto já está pronto para você começar a elaborar sua navegação.

Para fazer a prototipação desse App, usarei o Balsamiq Mockup, bem simples para você prototipar suas apps ou qualquer coisa. Se você tem a licença do Balsamiq, aqui está o código gerado do meu mockup, basta importar para a ferramenta e dá continuidade ou alterar.

mockup

Eu acabei chegando nessa configuração para esse novo App, é bem simples e funcional. O propósito desse App é ajudar você acompanhar hashtags ou termos utilizados no Twitter em um intervalo de tempo, ajudando você acompanhar as reações.

Navegando entre as views

Navegar entre as telas de uma App móvel é muito simples, e o pessoal da API bolou um esquema bem funcional, quando você imagina em telas você imagina a navegação saindo de um ponto A na tela A para um ponto B na tela B.
Apps móveis é 90% parecida com esse esquema de navegação, só que existem 2 fatores essenciais que as mudam, uma que a API só te leva de um ponto A da tela A para Tela B, não existe esse certo centrismo de um ponto específico para a outra tela; E o segundo fator que leva essa navegação é a maneira como você interage com ela, seja por toque ou seja por gesto, inverso do tradicional clique ou duplo clique de mouse.

navigator

Na imagem acima, você pode ver que a API utilizada pelo Flex para navegar entre Views, que é o componente principal de uma aplicação Flex Mobile é uma exclusiva palavra reservada que faz toda a diferença e dinâmica para trazer à vida sua App.

O “navigator”, é a palavrinha mágica que faz essa navegação, digamos que ela seja um Array que guarda o registro de cada tela, onde você executa alguns comandos básicos para navegar entre as views através dela. Esses comandos básicos são:

  • navigator.pushView(viewClass,data,context,transition);
  • navigator.popAll(transition);
  • navigator.popToFirstView(transition);
  • navigator.popView(transition);

Se você conhece bem de Array, sabe que comandos do tipo Pop, push, geralmente são associados a remoção e adição. É justamente isso que esses comandos faz, o primeiro o pushView, adiciona uma nova View ao navigator, o popAll, remove todas as Views do navigator, o popToFristView remove todas as telas, exceto a primeira, e o popView remove a View atual e volta para View anterior.

Definindo suas Views

Eu já sei como funciona a navegação, então vamos criar nossas Views, a primeira coisa que você deve pensar é em organiza-las, o Flash Builder deixa já por padrão dentro de um diretório views, eu particularmente gosto dessa configuração, deixando as views em um só diretório e colocando o inverse domain suas classes que irão manipula-la é quase perfeita sem precisa nenhum design pattern.

Minha primeira tela é a HomeView.mxml

home_view

Ela tem o seguinte código.

<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
		xmlns:s="library://ns.adobe.com/flex/spark"
		actionBarVisible="false" title="HomeView">
	<fx:Declarations>
		<!-- Place non-visual elements (e.g., services, value objects) here -->
	</fx:Declarations>
	<s:Rect width="100%" height="100%">
		<s:fill>
			<s:SolidColor color="#52a2cb"/>
		</s:fill>
	</s:Rect>
	<s:Image x="74" y="48" source="assets/logo.png"/>
	<s:Label x="56" y="357" color="#FFFFFF" text="20 Tags"/>
	<s:Label x="304" y="357" color="#FFFFFF" text="30 Menções"/>
	<s:Button x="73" y="428" width="333" height="65" label="Novo hashtag"
			  icon="assets/tag_add_48.png" skinClass="com.riacycle.skins.WhiteButtonSkin"/>
	<s:Button x="73" y="505" width="333" height="65" label="Hashtags pesquisadas"
			  icon="assets/book_bookmark_48.png" skinClass="com.riacycle.skins.WhiteButtonSkin"/>
	<s:Button x="73" y="580" width="333" height="65" label="Configurações"
			  icon="assets/gear_48.png" skinClass="com.riacycle.skins.WhiteButtonSkin"/>
</s:View>

A próxima tela que eu preciso criar é a NovaView.mxml

nova_view

<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
		xmlns:s="library://ns.adobe.com/flex/spark" title="Nova hashtag">
	<s:layout>
		<s:BasicLayout/>
	</s:layout>
	<fx:Declarations>
		<!-- Place non-visual elements (e.g., services, value objects) here -->
	</fx:Declarations>
	<s:navigationContent>
		<s:Button icon="assets/arrow_left_48.png"/>
	</s:navigationContent>
	<s:Button x="231" y="157" width="218" height="66" label="Adicionar" icon="assets/plus_48.png"
			  skinClass="com.riacycle.skins.WhiteButtonSkin"/>
	<s:Label x="43" y="51" color="#3A74CC" text="Termo"/>
	<s:TextInput x="42" y="82" width="403" height="64"/>
</s:View>

A próxima tela HashtagView.mxml é onde eu vou acompanhar as menções feitas pelos usuários do twitter.

hashtag_view

<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
		xmlns:s="library://ns.adobe.com/flex/spark" title="Termo: #exemplo">
	<fx:Declarations>
		<!-- Place non-visual elements (e.g., services, value objects) here -->
	</fx:Declarations>
	<s:navigationContent>
		<s:Button icon="assets/arrow_left_48.png"/>
	</s:navigationContent>
	<s:actionContent>
		<s:Button icon="assets/arrow_circle_right_48.png"/>
	</s:actionContent>
	<s:List left="2" right="2" top="2" bottom="2"></s:List>
</s:View>

E a última View necessária para montarmos nossa App é a ConfigView.mxml onde, algumas configurações básicas serão adicionadas ao nosso App, para deixar ele um pouco personalizado.

config_view

Com o seguinte código:

<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
		xmlns:s="library://ns.adobe.com/flex/spark" title="Configurações">
	<s:layout>
		<s:BasicLayout/>
	</s:layout>
	<fx:Declarations>
		<!-- Place non-visual elements (e.g., services, value objects) here -->
	</fx:Declarations>
	<s:navigationContent>
		<s:Button icon="assets/arrow_left_48.png"/>
	</s:navigationContent>
	<s:actionContent>
		<s:Button icon="assets/checkmark_48.png"/>
	</s:actionContent>
	<s:HSlider x="20" y="158" value="4"/>
	<s:Label x="19" y="37" text="Configurações gerais do App"/>
	<s:Label x="19" y="123" text="Intervalo entre consultas"/>
	<s:Label x="318" y="215" fontStyle="italic" text="Em minutos"/>
	<s:Button x="88" y="354" height="65" label="Apagar todo o histórico"
			  skinClass="com.riacycle.skins.WhiteButtonSkin"/>
	<s:Label x="22" y="317" text="Histórico de pesquisas"/>
</s:View>

Bem, até aqui nós definimos todas as Views que esse App pode apresentar, assim como um preview de cada dela, elas podem mudar no decorrer do artigo com algumas modificações simples e essenciais.

Para você acompanhar como ficou a organização do projeto, compartilho aqui o código fonte do projeto para você importar para seu Flash Builder.

Dica: Para salvar basta clicar no link com botão direito do mouse e escolher salvar como…

Até a próxima e última parte do artigo onde eu vou mostrar como codificar isso e publicar no Android Market.

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

Criando seu primeiro aplicativo Flex 4.5 Mobile para smartphones Android parte (1 de 3)

Depois de muito tempo sem tempo, olha que controvérsia, acabei com algumas horas livres essa tarde e aproveito para escrever esse post.
Quer criar Apps para Android com o Adobe AIR e Flex? Siga a receita abaixo para isso.

Ja é sabido de sua parte que o Flex cria apps nativas para Android de forma hiper simples. Se você é acostumado ao seu workflow de componentes, ciclos de vidas, você irá facilmente criar Apps elegantes, rápidas e intuitivas para dispositivos móveis.

O Framework do Flex, que usaremos é o Flex 4.5 com overlay do Adobe AIR 2.7, que conta com 4x mais performance do que o AIR 2.6. Em suma, o Flex roda em dispositivos móveis por que o AIR Run-time roda no Android.

Só que antes de você sair comprando ai seus dispositivos xing-lings ou baratinhos com o Android para testar suas criações artisticas, aconselho ler esse POST.

Para começar a brincadeira, você vai precisar de alguns ingredientes, vamos aos itens:

Antes de configurar alguma coisa, é super importante que você tenha em mente a seguinte afirmação. Eu entendo os riscos e serei um bom garoto(a), e nunca irei portar nenhum App meu com Datagrid de 100 registros dentro de uma App móvel, não farei Zilhões de operações.

Ok! Agora pode continuar.

Criando uma conta no Google e no Android Market

Esse passo é o mais simples que você encontrará nesse post, duvido que você não tenha uma conta no Google, vai dizer pajé que tu não tem um @gmail.com ? Uma continha perdida do Orkut? Ah! você vive em outro mundo que não é esse, volta para lá de onde tu veio vai! Esqueça isso de Mobile.

Ok, animos acalmados, criou a conta? Ah! Já tem? Ótimo, o próximo passo é registra-se no Android Market e se tornar um publicador de Apps lá. O processo é mega simples, entre no endereço https://market.android.com/publish/Home
android_publish_home.

Coloque seu login e senha e clique em Login, como você ainda é novato, vai aparecer outra tela perguntando seu Developer Name, dados de contato e telefone. Lembre-se coloque um nome de guerra, nome profissional, nada de vitinho, Vikky, Fofinha, LindinhadoAndroid, algo que passe credibilidade aos seus futuros usuários, Caso você seja uma empresa nem preciso fazer essas recomendações, basta colocar o nome da empresa que você quer usar como Developer Name no formulário.

android_publish_info

Clique agora em Continue.

Depois disso, você precisará dos

US$25 dolares

para fazer a sua inscrição no programa por 1 ano, se você tem conta no Google Checkout basta gastar por lá, caso contrário use algum cartão de crédito de qualquer bandeira que aceite transações internacionais.

android_publish_pagamento

Pronto, você está com a conta no Google Android Market criada e é só aguardar a liberação. Em média esse processo é quase imediato, em outros pode levar cerca de 1 dia no máximo. A coisa é rápida, então fica de olho no e-mail de boas vindas quando tudo for aceito pelo Google.

Aqui está minha dashboard no Android Market.

android_publish_dashboard

Configurando o Flex 4.5.1 SDK para usar o AIR 2.7 SDK

Como o SDK do Flex 4.5.1 ainda vem com suporte ao Adobe AIR 2.6 que é cerca de 4.x mais lento tanto no Android quanto no IOS, você vai precisar configurar seu SDK, esse processo agente chama de “SDK Overlay”, que é basicamente um CTRL+C e CTRL+V em alguns diretórios que sobrepõem arquivos antigos do AIR 2.6.

Baixou o AIR 2.7 SDK? Ok, feito isso extraia ele para um diretório de sua confiança, que seja simples de acessar. O pacote contendo o AIR 2.7 SDK tem os seguintes diretórios e arquivos.

air_2.7_sdk

Se você tem um igual, sinal que vai dar tudo certo, meio caminho andado.

Baixou o Flex 4.5.1 SDK? Ótimo, faça o mesmo processo do AIR 2.7 SDK e descompacte ele no seu diretório predileto, eu particularmente sempre deixo em um diretório meu chamado SDKs, porém nesse exemplo tem pessoas que gostam de deixar no mesmo diretório dos já existentes SDK do Flash Builder 4.5.1.

Ok, se você tem o SDK já descompactado, basta copiar o conteúdo da pasta onde você descompactou o AIR 2.7 SDK dentro da pasta do Flex 4.5.1. SDK. A idéia é sobrescrever os já existentes.

Feito? Ok, próximo passo é instalar o Flash Builder, a ferramenta perfeita para você criar suas apps, não só para Android como para outros devices, ios, BlackBerry Playbook, Web e Desktop.

Flash Builder Instalado? Perfeito, vamos agora configurar o ambiente Android para rodar sua app no console nativo que o próprio google disponibiliza.

Configurando o Android Console

Já tem o Java instalado em sua máquina? Então pule essa etapa, ela só serve mesmo para quem nunca usou o JDK ou tem apenas o JRE.

Para você testar no console, você precisa do JDK(Java Development Kit), que já vem tudo em um, então dependendo de seu sistema operacional, você precisará fazer alguns processos manuais, já no Windows é meio for dummies, é next-> next-> finish.

Baixou o correto referente ao seu OS? Instalou? Ótimo, pois agora precisamos definir as variáveis de ambiente do JAVA_HOME nas configurações globais do sistema operacional.

No Windows, vá em Iniciar – > Computador -> Botão direito do mouse -> Escolha propriedades -> Escolha aba Configurações Avançadas -> Variáveis de ambiente.

Adicione um novo registro na suas variáveis de ambiente com o nome JAVA_HOME. Olhe o exemplo abaixo.

jdk_java_home

Se você configurou tudo certinho, você pode testar no prompt do DOS do windows digitando java -version. Vai aparecer isso aqui ó.

java_version_console

Agora você está pronto para o Android SDK.

Baixando e configurando o Android SDK

Baixou o SDK? Então descompacte em um diretório de fácil acesso, eu coloquei o meu em C:/android-sdk. Para facilitar digitação de comandos.

Execute o SDK Manager, que é o carinha responsável por baixar todos os arquivos necessários do Android SDK da nave mãe Google.

android_avd

Pela primeira vez, esse processo dependendo de sua conexão com a internet, leva uma média de 1 hora para baixar todos os arquivos para seu computador.
Depois disso ele fica como o meu aqui.

android_sdk_dir

Ok, tudo configurado e instalado, vamos verificar se está mesmo. Com o mesmo comando que fiz para o java -version, usarei agora o comando adb version que é o Android Debug Bridge , para ver se executa corretamente.

android_adb

Se aparecer como na imagem acima, é sinal que tudo está correto e perfeito para criarmos nosso Android Emulator, onde iremos simular o sistema operacional Android. Prontos para esse passo?

Ah! Que esqueci, que depois que ele instalar tudo, ele vai pedir para você fechar o SDK Manager e abrir novamente, para que as alterações sejam aplicadas.

Criando o Android Emulator

Ok, volte agora ao SDK Manager e escolha a opção Virtual Devices.

android_virtual_devices

Veja que nesse meu eu já possuo 2 devices virtuais, para criar outro basta clicar em “New…”.

android_new_console

Preencha os dados de seu virtual device, assim como mostra na imagem acima, veja que eu não esqueci de criar usando o Android 2.2 API level 8, que é o necessário para o Adobe AIR rodar e consecutivamente o Flex. Como eu quero apenas testar a App nativa no dispositivo virtual eu deixei as outras configurações padrão, salvo apenas para a memória alocada de 100mb para esse console. Agora clique em “Create AVD”.

O AVD foi criado, só que agora falta executar, esse processo é bem gastante se você tem pouca memória na máquina, típicos 2GB, demora aproximadamente 20min até 30min para ele começar realmente executar, Eu por exemplo tenho 8Gb de memória e leva uma média de 5min. Se você tiver problemas na hora de executar veja se o JVM está setado corretamente.

Para executar, basta clicar em “Start…”.

android_starting

Essa tela preta é demorada, então aproveita e vai tomar um café, falar com sua tchutchuca.

….
……………
Passados alguns minutos. E eis que temos a tela inicial do Android rodando.

android_started

Android rodando, navegando na Web, agora só temos um problema, não temos o Adobe AIR instalado para testar a App, como fazer?

Instalando o Adobe AIR APK no seu emulador

Se você é por natureza curioso, dúvido você não ter bisbilhotado o SDK do Flex que você fez o overlay(Sobreposição) do AIR 2.7 no Flex 4.5.1 SDK. Abra esse diretório para você navegar nele, dentro do SDK você vai encontrar o nosso famoso AIR.apk que é necessário para rodar suas Apps.

air_apk_folder

Veja que eu fiz um mapinha de onde você vai achar o run-time do AIR para seu emulador Android, existem dois, para o Device e para o Emulador, você deve usar a versão Emulador, que é com ela que você vai conseguir emular alguma coisa. Resumindo eis aqui o caminho completo em minha máquina.

C:Program Files (x86)AdobeAdobe Flash Builder 4.5sdks4.5.1_air2.7runtimesairandroidemulator

Lembre-se seu índio, que o diretório na sua máquina pode ser diferente, se não você vai reclamar depois nos comentários que não consegiu achar o tal APK.

Eu copiei o meu para esse exemplo para o diretório raiz, C:/ para facilitar agora o processo de digitação pelo prompt de comando.

Abra o CMD(MS-DOS), e digite o comandos abaixo.

adb devices

adb_devices_list

Se aparecer o nosso Emulador em execução,é por que está tudo OK.

Para instalar é super simples, digite o comando.

adb install {NOME-DO-EMULADOR} c:/Runtime.apk

adb_devices_install_sucess

Finalmente terminamos essa parte chata de configurar a máquina, seu Adobe AIR está funcionando perfeitamente no seu device, Só que como é que eu sei que ele está instalado? Tem 2 formas, vê se o resultado do comando de instalar deu certo e também indo no Emulador, clicar em
Settings -> Applications-> Manage Applications; E você vai ver o Adobe AIR instalado lá.

air_installed

Tudo pronto, agora só abrir o Flash Builder já instalado e começar com sua App Hello World. Nos vemos na próxima Etapa.

Aproveite e participe do grupo de discussão Flex-Mobile

Flex/ Flex 4/ Flex 4.5

Flex comunicando com o Skins

É possível fazer isso no mundo de duas formas, sendo um super herói ou sendo um framework do Flex. 😀

Criar skins é maravilhoso no Flex, você faz seu sistema ganhar vida, uma vida não só fantástica mais uma vida dinamica. Alguns tem dúvidas quanto e como fazer isso fluir de forma simples.

A explicação mais clara e objetiva que eu posso dar é : Veja o Camaleão. Sua pele é altamente camuflável e adaptada a qualquer terreno. Skins no Flex é justamente isso, adaptar o feio em bonito. Embora o camaleão continue feio, mudando só sua cor.

Vejamos o exemplo vivo abaixo

Requer o Flash Player

Agora veja como é feito, eu crio um novo Skin no Flash Builder com as seguintes caracteristicas.

Arquivo MySkin.mxml

<?xml version="1.0" encoding="utf-8"?>
 
<s:Skin 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.disabled="0.5">
 
    <fx:Metadata>
    <![CDATA[
        /**
         * @copy spark.skins.spark.ApplicationSkin#hostComponent
         */
        [HostComponent("MyContainer")]
    ]]>
    </fx:Metadata>
 
    <s:states>
        <s:State name="normal" />
        <s:State name="disabled" />
    </s:states>
 
    <!--- Defines the appearance of the SkinnableContainer class's background. -->
    <s:Ellipse width="{hostComponent.raio}" height="{hostComponent.raio}" id="background" verticalCenter="0" horizontalCenter="0">
        <s:fill>
            <!--- @private -->
            <s:SolidColor id="bgFill" color="{hostComponent.color}"/>
        </s:fill>
    </s:Ellipse>
 
    <!--
        Note: setting the minimum size to 0 here so that changes to the host component's
        size will not be thwarted by this skin part's minimum size.   This is a compromise,
        more about it here: http://bugs.adobe.com/jira/browse/SDK-21143
    -->
    <!--- @copy spark.components.SkinnableContainer#contentGroup -->
    <s:Group id="contentGroup" left="0" right="0" top="0" bottom="0" minWidth="0" minHeight="0">
        <s:layout>
            <s:BasicLayout/>
        </s:layout>
    </s:Group>
 
</s:Skin>

A comunicação do skin com o componente que vai usa-lo, se dá pela palavrinha reservada hostComponent, veja que no meu tag Ellipse, eu uso ele para mudar a largura e altura usando a propriedade raio que é uma propriedade do componente que eu tenho e irei usar.

Outro detalhe é que esse skin eu seto quem será o host, ou seja quem hospedará ele.

   <fx:Metadata>
    <![CDATA[
        /**
         * @copy spark.skins.spark.ApplicationSkin#hostComponent
         */
        [HostComponent("MyContainer")]
    ]]>
    </fx:Metadata>

No Caso eu tenho o componente MyContainer

Que tem o seguinte código:

Arquivo MyContainer.mxml

<?xml version="1.0" encoding="utf-8"?>
<s:SkinnableContainer xmlns:fx="http://ns.adobe.com/mxml/2009"
					  xmlns:s="library://ns.adobe.com/flex/spark"
					  xmlns:mx="library://ns.adobe.com/flex/mx" width="400" height="300"
					  skinClass="MySkin">
	<s:layout>
		<s:BasicLayout/>
	</s:layout>
	<fx:Script>
		<![CDATA[
 
 
			[Bindable]private var _color:uint = 0x000000;
			[Bindable]private var _raio:Number = 100;
 
 
			[Bindable]
			public function get raio():Number
			{
				return _raio;
			}
 
			public function set raio(value:Number):void
			{
				_raio = value;
			}
 
			[Bindable]
			public function get color():uint
			{
				return _color;
			}
 
			public function set color(value:uint):void
			{
				_color = value;
			}
 
		]]>
	</fx:Script>
</s:SkinnableContainer>

E para usar basta eu arrastar meu Container para tela e setar via CSS ou até mesmo direto no container a propriedade skinClass.

<s:SkinnableContainer xmlns:fx="http://ns.adobe.com/mxml/2009"
					  xmlns:s="library://ns.adobe.com/flex/spark"
					  xmlns:mx="library://ns.adobe.com/flex/mx" width="400" height="300"
					  skinClass="MySkin">

E aqui é o código de App que você viu lá em cima.

<?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"
			   xmlns:ns1="*"
			   width="385" height="340" minWidth="955" minHeight="600">
 
	<fx:Script>
		<![CDATA[
			protected function changeMyCompInnerSize(event:Event):void
			{
				MyComp.raio = radioChanger.value;
			}
		]]>
	</fx:Script>
 
	<s:HSlider id="radioChanger" x="143" y="303"
			   change="changeMyCompInnerSize(event)" maximum="500" minimum="10"
			   stepSize="1"/>
 
	<ns1:MyContainer color="#84C239" id="MyComp" x="59" y="35" width="265" height="229">
		<s:Label text="hello World" verticalCenter="0" horizontalCenter="0"/>
	</ns1:MyContainer>
 
</s:Application>

Fácil não? Os skins realmente são salvadores da pátria, você consegue absorver muita e transformar o que era complexo em simples. Vejamos outro exemplo abaixo.

Nesse exemplo eu usei de forma bem simples o Gauge Chart , uma pequena demonstração de como Skins podem nos ajudar e muito, principalmente criar gráficos.

Requer o Flash Player

Aqui abaixo você ver o código fonte da App de cima.

 
<?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"
			   xmlns:ns1="*"
			   width="581" height="362" minWidth="955" minHeight="600">
 
	<fx:Script>
		<![CDATA[
			protected function mudarValor(event:Event):void
			{
				// TODO Auto-generated method stub
				grafico.value = valorChanger.value;
			}
 
			protected function mudarPressao(event:Event):void
			{
				// TODO Auto-generated method stub
				pressaoChart.value = pressaoValor.value;
			}
 
		]]>
	</fx:Script>
 
	<fx:Declarations>
		<!-- Place non-visual elements (e.g., services, value objects) here -->
	</fx:Declarations>
	<ns1:MyGauge id="grafico" x="30" y="70" width="240" height="240">
	</ns1:MyGauge>
	<s:HSlider id="valorChanger" x="108" y="330" change="mudarValor(event)" maximum="360" minimum="0"
			   stepSize="1" value="90"/>
	<s:HSlider id="pressaoValor" x="399" y="331" change="mudarPressao(event)" maximum="360" minimum="0"
			   stepSize="1" value="90"/>
	<s:Label x="321" y="330" text="Valor"/>
	<s:Label x="30" y="329" text="Valor"/>
	<s:Label x="39" y="41" fontSize="22" text="Análise do Dosador"/>
	<s:Label x="313" y="40" fontSize="22" text="Pressão no catalizador"/>
	<ns1:MyGauge value="220" fillColors="{[0xe70505,0xb40909]}" id="pressaoChart" x="301" y="70" width="240" height="240">
	</ns1:MyGauge>
</s:Application>

O Componente MyGaugue.mxml

<?xml version="1.0" encoding="utf-8"?>
<s:SkinnableContainer skinClass="GaugeSkin" xmlns:fx="http://ns.adobe.com/mxml/2009"
					  xmlns:s="library://ns.adobe.com/flex/spark"
					  xmlns:mx="library://ns.adobe.com/flex/mx" >
	<fx:Declarations>
		<!-- Place non-visual elements (e.g., services, value objects) here -->
	</fx:Declarations>
	<fx:Script>
		<![CDATA[
 
			[Bindable]private var _value:Number = 90;
			[Bindable]private var _ponteiroColor:uint = 0x000000;
			[Bindable]private var _fillColors:Array = [0x6FC9FF,0x5380D0];
 
 
 
			[Bindable]
			public function get fillColors():Array
			{
				return _fillColors;
			}
 
			public function set fillColors(value:Array):void
			{
				_fillColors = value;
			}
 
			[Bindable]
			public function get ponteiroColor():uint
			{
				return _ponteiroColor;
			}
 
			public function set ponteiroColor(value:uint):void
			{
				_ponteiroColor = value;
			}
 
			[Bindable]
			public function get value():Number
			{
				return _value;
			}
 
			public function set value(value:Number):void
			{
				_value = value;
			}
 
		]]>
	</fx:Script>
</s:SkinnableContainer>

E finalmente o código do GaugeSkin.xml

<?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 a Spark SkinnableContainer container.
 
     @see spark.components.SkinnableContainer
 
      @langversion 3.0
      @playerversion Flash 10
      @playerversion AIR 1.5
      @productversion Flex 4
-->
<s:Skin 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.disabled="0.5">
 
    <fx:Metadata>
    <![CDATA[
        /**
         * @copy spark.skins.spark.ApplicationSkin#hostComponent
         */
        [HostComponent("MyGauge")]
    ]]>
    </fx:Metadata>
 
    <s:states>
        <s:State name="normal" />
        <s:State name="disabled" />
    </s:states>
 
    <!--- Defines the appearance of the SkinnableContainer class's background. -->
	<s:Group width="100%" height="100%">
 
 
	<s:Ellipse width="100%" height="100%">
		<s:fill>
			<s:LinearGradient rotation="90">
				<s:GradientEntry alpha="1.0" color="{hostComponent.fillColors[0]}" ratio="0"/>
				<s:GradientEntry alpha="1.0" color="{hostComponent.fillColors[1]}" ratio="1"/>
			</s:LinearGradient>
		</s:fill>
	</s:Ellipse>
	<s:Rect x="{Math.ceil(hostComponent.width*0.5)}" y="0" width="10" height="{hostComponent.width/2}"
			rotation="{hostComponent.value}" transformX="5"
			transformY="{Math.ceil(hostComponent.width*0.5)}">
		<s:fill>
			<s:SolidColor color="{hostComponent.ponteiroColor}"/>
		</s:fill>
	</s:Rect>
	<s:RichText  horizontalCenter="0" y="30" color="#ffffff" fontFamily="Arial" fontSize="14" fontWeight="bold"
				tabStops="S0 S50" text="{hostComponent.value}"/>
	</s:Group>
    <!--
        Note: setting the minimum size to 0 here so that changes to the host component's
        size will not be thwarted by this skin part's minimum size.   This is a compromise,
        more about it here: http://bugs.adobe.com/jira/browse/SDK-21143
    -->
    <!--- @copy spark.components.SkinnableContainer#contentGroup -->
    <s:Group id="contentGroup" left="0" right="0" top="0" bottom="0" minWidth="0" minHeight="0">
        <s:layout>
            <s:BasicLayout/>
        </s:layout>
    </s:Group>
 
</s:Skin>

Até a próxima e bons estudos com Skins.

Android/ Flex/ Flex 4.5/ Flex Mobile Framework

Novo grupo on-line para discutir Flex em dispositivos móveis

Hoje abrimos um espaço para tirar dúvidas relacionadas ao Flex só que com foco em mobilidade.

O grupo é uma extensão do atual Flex-Brasil, onde fica mais fácil focar e ajudar desenvolvedores que queiram utilizar o Flex em dispositivos móveis.

Já tem 45 inscritos, então se você quer discutir sobre Flex em Smartphones e Tablets, lá será o melhor lugar.


http://groups.google.com/group/flex-mobile

Participe, é grátis!

Flex/ Flex 4/ Flex 4.5/ JQuery

Redescobrindo o gosto pelos padrões Web : JQuery para devs Flex – Parte 4

Estou fascinado como ambas tecnologias possuem suas particularidades e ao mesmo tempo compartilham tantas coisas em comum. Se por um lado aprender Javascript é parte fundamental para seu progresso com JQuery, serve a mesma deixa para Flex, que depende exclusivamente de Actionscript.

Embora a zona de conforto que o Flex lhe proporciona como design padrão já pre-definido, layout Manager já ajustadinho para qualquer tela, composição de componentes, arquitetura componentizada, tudo isso acarreta na escolha de se adotar ou não JQuery e padrões Web em seus projetos e em sua carreira profissional.

Fato é, que da uma preguiça fora de sério aprender tudo isso novamente, como denominar dependências e heranças com DOM, live encoding. É deverás complicado para quem sai de outro idioma programático e cai de pará-quedas no ambiente do navegador.

Nessa quarta parte, quero mostrar em diante como é a estrutura padrão de eventos no JQuery e como isso pode encurtar pontos no aprendizado.

Eventos

A gramática de eventos no Flex é composta por pacotes e mais pacotes definhados por componentes e seus containers, tanto que é muito bem distribuído, é como se fosse 1 caixa de palito de fósforo, contendo palitos com respectivas funções programáticas, um para cada tipo de fogo que se pretende ascender.
É estimado que por padrão no Flex 4.5 existam cerca de 98 tipos de evento, boa parte eles são herdeiros do evento chave que fica no pacote flash.events.Event os demais são de uso exclusivo de cada plataforma como AIR e Flash Player.

Já a gramática de eventos do JQuery, é um tanto simplificada, onde não passa mais que 36 tipos eventos, todos herdeiros de um só evento pai que é amarrado ao HTML, o DOM Object.

Porém, essa maneira simplista da coisa tem seu certo fundo técnico, uma vez que você tem N tipos de navegadores com N tipos de engine, ou você simplifica a coisa ou acaba fadado ao fracasso. Não tão distante, por mais que você queira relutar, os eventos no Flex também seguem um padrão cronológico ou técnico possa se dizer, do modelo de DOM level 3. Onde há uma certa semelhança em nomenclatura e a estrutura de como funciona, tal como adicionar listener, remover listener.

O que o JQuery fez foi pegar tudo isso e simplificar o máximo possível, trazendo ao desenvolvedor maior facilidade nessa execução de eventos. Porém em contra partida ele pecou pela exclusão do processo de fase, o que é umas das partes fundamentais em aplicações que tomam por base eventos.

Exemplo prático:

Criar um Div ( Bloco), onde ele siga a posição do mouse. Uns dos segredos desse exemplo é o CSS, com seu subselector position:relative;

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Untitled Document</title>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
<style type="text/css">
.bloco {width:200px; height:200px; background:#000; display:block; position:relative;}
</style>
<script type="text/javascript">
 
	$(document).ready(function(e) {
 
		// começar a brincadeira com JQuery
 
			$(document).mousemove(function(e) {
                	$(".bloco").css("left",e.pageX);
					$(".bloco").css("top",e.pageY);
					var nova_cor = 'rgb(' + (Math.floor((-256)*Math.random()) + 200) + ','
                     + (Math.floor((-55)*Math.random()) + 200) + ','
                     + (Math.floor((-55)*Math.random()) + 200) + ')';
					$(".bloco").css("background",nova_cor);
            });
			$(document).mouseout(function(e) {
               setInterval(loop,4000);
            });
 
			function loop()
			{
				$(".bloco").animate({left:Math.random()*  screen.availWidth/2},1000);
				$(".bloco").animate({top:Math.random()* screen.height/2},1000);
			}
 
    });
</script>
</head>
 
<body>
			<div class="bloco"></div>
</body>
</html>

Se eu fizer esse exemplo no Flex, como seria?

 
<?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="init(event)">
 
	<fx:Declarations>
		<s:Move id="mover" target="{bloco}" duration="4000" />
	</fx:Declarations>
	<fx:Script>
		<![CDATA[
			import mx.events.EffectEvent;
			import mx.events.FlexEvent;
			import mx.events.FlexMouseEvent;
 
			protected function init(event:FlexEvent):void
			{
				this.addEventListener(MouseEvent.MOUSE_MOVE,mudarBloco);
				this.addEventListener(MouseEvent.ROLL_OUT,randomizar);
				this.addEventListener(MouseEvent.ROLL_OVER,pegarListeners);
 
			}
 
			protected function mudarBloco(event:MouseEvent):void
			{
				bloco.x = mouseX;
				bloco.y = mouseY;
				cor.color = Math.random()*0xffffff;
			}
 
			protected function randomizar(event:MouseEvent):void
			{
				mover.xTo = Math.random()* screen.width/2;
				mover.yTo = Math.random()* screen.height/2;
				mover.play();
				this.removeEventListener(MouseEvent.ROLL_OUT,randomizar);
 
			}
 
			protected function pegarListeners(event:MouseEvent):void
			{
				// TODO Auto-generated method stub
 
				this.addEventListener(MouseEvent.ROLL_OUT,randomizar);
			}
 
		]]>
	</fx:Script>
	<s:Rect id="bloco" width="200" height="200">
		<s:fill>
				<s:SolidColor id="cor"/>
		</s:fill>
	</s:Rect>
</s:Application>

Viu que tudo não passa de mousemove, mouseOut, posição do mouse. Tudo é igual, o que realmente muda nesse exemplo é a nomenclatura das palavras chaves usadas.

Uma simples lista de tarefa no JQuery

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Untitled Document</title>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
<link href="css/padrao.css" rel="stylesheet" type="text/css">
 
<script type="text/javascript">
 
	$(document).ready(function(e) {
 
			$("#btn").click(function(e) {
                	// adicionar itens
					$("#tarefas").append('<li><input name="Tete" type="checkbox" value="'+$('input').val()+'"><label>'+$('input').val()+'</label></li>');
					$('input').val('');
					$('input').focus();
            });
    });
</script>
</head>
 
<body>
<input class="input" name="tarefa" type="text" lang="pt" value="Digite sua tarefa" size="30" maxlength="50">
<a id="btn" class="button green large">+</a>
 
<ul id="tarefas" class="lista">
</ul>
</body>
</html>

Até ai tudo bem, e se você quiser dinamicamente adicionar um evento sempre que um novo item é adicionado, você faz através do evento bind (), que é próprio para isso.

					$('li input').bind('change',function (e){
						if($("li input").is(':checked')){
							$(this).toggle();
						}
					});

O código fica no final

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Untitled Document</title>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
<link href="css/padrao.css" rel="stylesheet" type="text/css">
 
<script type="text/javascript">
 
	$(document).ready(function(e) {
 
			$("#btn").click(function(e) {
                	// adicionar itens
					$("#tarefas").append('<li><input name="Tete" type="checkbox" value="'+$('input').val()+'"><label>'+$('input').val()+'</label></li>');
 
					$('li input').bind('change',function (e){
						if($("li input").is(':checked')){
							$(this).toggle();
						}
					});
					$('input').val('');
					$('input').focus();
            });
 
    });
</script>
</head>
 
<body>
<input class="input" name="tarefa" type="text" lang="pt" value="Digite sua tarefa" size="30" maxlength="50">
<a id="btn" class="button green large">+</a>
 
<ul id="tarefas" class="lista">
</ul>
</body>
</html>

E com isso você pode partir para exemplos mais sofisticados como um dataGrid por exemplo:

Veja abaixo

jquerytabela

Tem editar, selecionar tudo, soma de valores.

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Untitled Document</title>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
<link href="css/padrao.css" rel="stylesheet" type="text/css">
 
<script type="text/javascript">
 
 
 
	$(document).ready(function(e) {
		editable();
		disable();
 
 
 
		$("#checkAll").change(function(e) {
 
			 $("table td input").each(function(index, element) {
 
								if($("#checkAll").is(':checked')){
									$(element).attr("checked",true);
								}
								else{
									$(element).attr("checked",false);
								}
							///	alert($(element).val());
 
					});
        });
 
		var count = 1;
		$("#addMaisButton").click(function(e) {
			if(count == 1){
  			$("table").append('<tr class="d1"><td><input class="checkbox" type="checkbox"></td><td></td><td></td></tr>');
			count++;
			}else if(count == 2)
			{
				$("table").append('<tr class="d2"><td><input class="checkbox" type="checkbox"></td><td></td><td></td></tr>');
				count--;
			}
			editable();
        });
 
    });
 
	function disable()
	{
			$("table tr td:first-child").each(function(index, element) {
                	$(element).unbind('dblclick');
					$(element).unbind('keyup');
					$(element).unbind('focusout');
            });
 
	}
	function editable(e)
	{
		$("table tr td").each(function(index, element) {
 
				$(element).bind("dblclick",function edit(){
					$(element).html('<input class="input" type="text" value="'+$(element).text()+'" size="30" maxlength="50">');
					$('input').bind('focus',function focusEdit(){this.select()});
				});
 
				$(element).bind("keyup",
						function closeEdit(e){
							if(e.keyCode == 13){
							$(element).text($(element).find('input').val());
							somarTotal();
							}
				});
            });
 
	}
 
	function somarTotal()
	{
			var somageral = 0;
			$("table tr td:nth-child(3)").each(function(index, element) {
					//	somageral += ;
						if(!isNaN(parseInt($(element).text()))){
							somageral += parseInt($(element).text());
							//alert($(element).text());
						}
 
            });
			//alert(total);
		$(".total").text(somageral + ',00');
	}
</script>
</head>
 
<body>
<a class="button green large" id="addMaisButton">Adicionar +</a>
<table class="grid" width="650" border="0" cellpadding="10">
  <tr>
    <th width="26" scope="col">
      <input name="checkAll" type="checkbox" class="checkbox" id="checkAll"></th>
    <th width="340" scope="col">Descrição dos itens</th>
    <th width="184" scope="col">Valor</th>
  </tr>
  <tr class="d1">
    <td class=""> <input name="checkAll1" type="checkbox" class="checkbox" id="checkAll1"></td>
    <td>q</td>
    <td>10</td>
  </tr>
  <tr class="d2">
    <td class=""><input class="checkbox" type="checkbox" name="checkAll2" id="checkAll2"></td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr class="d1">
    <td class=""><input class="checkbox" type="checkbox" name="checkAll3" id="checkAll3"></td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr class="d2">
    <td class=""><input class="checkbox" type="checkbox" name="checkAll4" id="checkAll4"></td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
</table>
<p>&nbsp;</p>
<p>Soma Total:R$<span class="total"></span></p>
</body>
</html>

Estude o código e veja como fiz, eu gastei uma média de 4 horas para fazer isso. Embora o código não esteja optimizado.

Abraços e até o próximo.

AIR Mobile/ Flex/ Flex 4.5

Ganhamos no desafio do Melhor App Flex de Open Source no Flashcamp Brasil 2011

Notícia excelente, além de termos noticiado aqui e aqui , que haviamos criado o app para o Flashcamp Brasil no Android, nós decidimos abrir o código fonte do mesmo para participar do desafio do evento.

Não deu outra, acabamos por ganhar como melhor App Flex Open-source. O app é para plataforma mobile Android, onde todo e qualquer desenvolvedor que domine o Flex/AIR, possa criar um App similar para outros eventos de tecnologia ou não e assim fomentar a informação para quem participa dos eventos por ai à fora.

Muito bom ganhar um desafio, esse foi o primeiro que participamos. Parabéns aos outros ganhadores em outras categorias.

Flex/ Flex 4.5/ Flex Mobile Framework

Problemas para atualizar Flash Builder 4.5 para 4.5.1 ?

Você já tinha suporte nativo para criar apps para Android no Flash Builder 4.5, porém com o recém lançado 4.5.1 você não faz apenas Android, mas para ios e BlackBerry Playbook.

E isso tem atraído muita gente na esperança de criar apps Flex para mobile, tanto é que alguns colocam defeito no Flex, achando que só serve para Android, o fato é que se você não atualiza, você vai passar batido.

O grande problema é que para atualizar, muita gente acostumada com o Eclipse vai em Help > Search Product Update. Vai ver que não é bem por ai.

Especialmente no Flash Builder a Adobe em conjunto com a suite CS 5.5 criaram um mecanismo que se atualiza. Basta usar o menu corretamente.

help_flex

Siga os passos corretamente e você terá atualizado o seu Flash Builder.

Existem casos especiais que nem assim funciona, nesse caso você baixa manualmente o update e instala, Lembre-se de fechar o Flash Builder antes de fazer isso.
Acesse esse link e baixa a versão que corresponde ao seu OS.

Flex/ Flex 4/ Flex 4.5/ HTML 5/ JQuery

Redescobrindo o gosto pelos padrões Web : JQuery para devs Flex – Parte 2

Continuando com as minhas descobertas, descritas nesse post. Gostaria de comentar algumas comparações para desenvolvedores Flex que queiram aprender JQuery.

Alguns aspectos interessantes

Mudança de propriedade em tempo de execução (tempo real)

Flex: Facilmente no Flex você muda propriedades em tempo de execução, através de várias formas, com CSS(StyleManager), Skin, Skinnable Class, Reflection e Actionscript.
Imagine o código abaixo do Flex, onde você tem um Rect (Retangulo) e você quer mudar sua largura e altura depois de 4 segundos que a App disparou o CreationComplete.

<?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" creationComplete="init(event)">
	<fx:Declarations>
		<!-- Place non-visual elements (e.g., services, value objects) here -->
	</fx:Declarations>
 
	<fx:Script>
		<![CDATA[
			import mx.events.FlexEvent;
 
			private var tempo:Timer;
 
 
			protected function init(event:FlexEvent):void
			{
				// TODO Auto-generated method stub
				tempo = new Timer(4000);
				tempo.addEventListener(TimerEvent.TIMER,executar);
				tempo.start();
			}
			private function executar(e:TimerEvent):void
			{
				alvo.width = 100;
				alvo.height = 100;
				tempo.stop();
			}
 
		]]>
	</fx:Script>
 
	<s:Rect id="alvo" x="109" y="53" width="200" height="200">
			<s:fill>
				<s:SolidColor color="#000000"/>
			</s:fill>
	</s:Rect>
</s:Application>

Basicamente a única coisa que você precisa é da classe Timer e 2 métodos para mudança.

JQuery: Se eu for fazer isso no JQuery, basicamente eu uso do JQuery só a facilidade de chegar até o objeto e usar o método .css para alterar as propriedades, o resto é puro Javascript, eu faria assim.

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 
<style type="text/css">#alvo { width:200px; height:200px; background:#000; position:relative; top:40px; left:140px;}</style>
 
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
<script type="text/javascript">
 $(document).ready(function(e) {
    // inicia o documento
 
	var tempo = setTimeout("mudarPropriedades()",4000);
});
function mudarPropriedades(){
			$("#alvo").css("width",100);
			$("#alvo").css("height",100);
}
</script>
</head>
<body>
		<div id="alvo"></div>
</body>
</html>

Fácil, não? Esse assunto acaba levando a outro assunto que é estilo.

Estilo CSS

Flex:Uma das grandes facilidades que o Flex 4.x, tem é seu novo esquema de CSS, que é baseado na especificação nova do CSS 3, que é justamente a inclusão de namespaces para facilitar a compatibilidade e não só isso, como também sub selectors, typed selectors e os media query para diferentes telas (Multi-screen). O que era uma enorme desvantagem nas versões anteriores 2.x e 3.x que ainda eram baseadas na especificação CSS 2, que diga-se de passagem não suportava tudo do CSS2.

Tanto que o negócio era tão ruim no Flex 2.x e 3.x que tinha-se espaço para o Flex Style Explorer, eu achava isso um salvador da pátria. Já que programmatic skin era uma coisa horrível de se fazer.

Graças aos com noção, isso foi banido do novo Flex 4.x SDK e a coisa agora está uma maravilha. Então baseando-se na nova. como eu estilizo meus componentes em Flex via CSS?

O código abaixo me gera isso ai.
button

<?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">
	<fx:Style>
		@namespace s "library://ns.adobe.com/flex/spark";
		@namespace mx "library://ns.adobe.com/flex/mx";
 
		s|Button {
				chromeColor:#000000;
				fontSize:20;
				color:#ffffff;
		}
	</fx:Style>
 
	<s:Button x="100" y="200" width="149" height="46" label="Hello World"/>
</s:Application>

JQuery: Na verdade nem seria JQuery e sim, CSS3 padrão, já que o CSS é uma linguagem de estilos para o HTML, isso teria mais sentindo se eu aplicasse o CSS 3 em um documento HTML 5, que a compatibilidade é quase 100%. Então para aplicar como eu faria?

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Blogs Post</title>
 
<style type="text/css">
.Button, .Button:visited {
	zoom: 1; /* zoom and *display = ie7 hack for display:inline-block */
	*display: inline;
	vertical-align: baseline;
	margin: 0 2px;
	outline: none;
	cursor: pointer;
	text-align: center;
	text-decoration: none;
	font: 14px/100% Arial, Helvetica, sans-serif;
	padding: .5em 2em .55em;
	text-shadow: 0 1px 1px rgba(0,0,0,.3);
	-webkit-border-radius: .5em;
	-moz-border-radius: .5em;
	border-radius: .5em;
	-webkit-box-shadow: 0 1px 2px rgba(0,0,0,.2);
	-moz-box-shadow: 0 1px 2px rgba(0,0,0,.2);
	box-shadow: 0 1px 2px rgba(0,0,0,.2);
}
.black {
	color: #d7d7d7;
	border: solid 1px #333;
	background: #333;
	background: -webkit-gradient(linear, left top, left bottom, from(#666), to(#000));
	background: -moz-linear-gradient(top,  #666,  #000);
	filter:  progid:DXImageTransform.Microsoft.gradient(startColorstr='#666666', endColorstr='#000000');
}
</style>
 
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
<script type="text/javascript">
 $(document).ready(function(e) {
    // inicia o documento
 
	var tempo = setTimeout("mudarPropriedades()",4000);
});
function mudarPropriedades(){
			$("#alvo").css("width",100);
			$("#alvo").css("height",100);
}
</script>
</head>
 
</head>
<body>
	<a class="Button black">Hello World</a>
</body>
</html>

Veja que se você salvar esse html e executar, ele vai te trazer a mesma aparência arredondada de um button padrão do Flex, uma coisa que me deixou desconfortável nesse ponto, foi o fato de ter que fazer N hacks e filtros para funcionar igual como no Flex, depois caiu a ficha e eu lembrei que o Flex para tornar isso fácil, ele já pre-define isso, então estão equiparados. Porém é compatível a aparência, só que no CSS e HTML como a linguagem é diferente do Flex que é compilada e no HTML e CSS3 ela é interpretada pelo navegador, eis o motivo dessa discrepância de aparência entre navegadores e o real motivo para os hacks em CSS3.

Módulos e modularizar Apps

Flex: Módulos, você tem ModuleLoader, Module, e uma cacetada de técnicas e teorias para deixar sua app leve e rápida, é um assunto extenso e não me cabe colocar aqui todo o assunto em poucos paragráfos, o assunto para mais de manga.
Em fim, em resumo, se você quer deixar a App leve, você modulariza ela em swf separados e os carrega apenas quando for necessário. A técnica mais básica para fazer isso, seria assim:

<?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">
 
	<fx:Script>
		<![CDATA[
			protected function button1_clickHandler(event:MouseEvent):void
			{
				mdContainer.unloadModule();
				mdContainer.loadModule("moduloA.swf");
			}
 
			protected function button2_clickHandler(event:MouseEvent):void
			{
				mdContainer.unloadModule();
				mdContainer.loadModule("moduloB.swf");
			}
 
		]]>
	</fx:Script>
 
	<s:controlBarContent>
	<s:Button label="Carregar Modulo A" click="button1_clickHandler(event)"/>
	<s:Button label="Carregar Modulo B" click="button2_clickHandler(event)"/>
</s:controlBarContent>
	<s:ModuleLoader id="mdContainer" width="100%" height="100%" >
 
	</s:ModuleLoader>
</s:Application>

Você descarrega o módulo anterior caso exista e carrega o próximo. Fácil não?

JQuery: O JQuery traz a tona um funcionamento muito similar a API do Flash que é para Carregar coisas , a Classe Loader, que é uma subclass do LoaderInfo, assim como o ModuleLoader.

No JQuery ele faz esse processo através do método .load ().

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Blogs Post</title>
 
<style type="text/css">
#Menu {
		width:100%;
		height:40px;
		display:block;
		position:fixed;
}
.meusModulos{ position:absolute; margin-top:44px; width:500px; height:500px;background:#f4f4f4;}
 
.Button, .Button:visited {
	zoom: 1; /* zoom and *display = ie7 hack for display:inline-block */
	*display: inline;
	vertical-align: baseline;
	margin: 0 2px;
	outline: none;
	cursor: pointer;
	text-align: center;
	text-decoration: none;
	font: 14px/100% Arial, Helvetica, sans-serif;
	padding: .5em 2em .55em;
	text-shadow: 0 1px 1px rgba(0,0,0,.3);
	-webkit-border-radius: .5em;
	-moz-border-radius: .5em;
	border-radius: .5em;
	-webkit-box-shadow: 0 1px 2px rgba(0,0,0,.2);
	-moz-box-shadow: 0 1px 2px rgba(0,0,0,.2);
	box-shadow: 0 1px 2px rgba(0,0,0,.2);
}
.black {
	color: #d7d7d7;
	border: solid 1px #333;
	background: #333;
	background: -webkit-gradient(linear, left top, left bottom, from(#666), to(#000));
	background: -moz-linear-gradient(top,  #666,  #000);
	filter:  progid:DXImageTransform.Microsoft.gradient(startColorstr='#666666', endColorstr='#000000');
}
</style>
 
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
<script type="text/javascript">
 $(document).ready(function(e) {
    // inicia o documento
 
	$("#btnA").click(function(){
			$("#moduleLoaderHTML").load("moduloA.html");
	});
	$("#btnB").click(function(){
			$("#moduleLoaderHTML").load("moduloB.html");
	});
});
 
</script>
</head>
 
</head>
<body>
	<div id="Menu">
	<a class="Button black" id="btnA">Carregar Modulo A</a>
    <a class="Button black" id="btnB">Carregar Modulo B</a>
    </div>
 
    <div class="meusModulos" id="moduleLoaderHTML"></div>
</body>
</html>

Os módulos basicamente são iguais, então posto aqui só modulo A o modulo B tem o mesmo código.

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Untitled Document</title>
<style type="text/css">
#estilos {background:#000; height:100% !important}
h2 {color:#fff; size:40px;}
</style>
</head>
 
<body >
<div id="estilos">
<h2>Modulo A Carregado com sucesso!</h2>
</div>
</body>
</html>

Tem uma infinidade de funções no JQuery, HTML e CSS que me fascinam, acho que vou colocar por aqui. Até a parte 3.

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.