Você está na página 1de 161

Dominando

Adobe Flex Mobile

Daniel Pace Schmitz


Atenção

Este ebook não é gratuito. Contribua com a qualidade desta obra e com o
desenvolvimento de novos livros digitais. Não retransmita este documento.
Ajude o autor a criar mais obras de qualidade e ajude-o a pagar as suas contas

Caso tenha obtido esta obra por outros meios, você


ainda pode me ajudar realizando a compra do mesmo, no site:

http://www.danielschmitz.com.br

Obrigado!

Pegou no torrent ??? Fuuuuuuuu

Corra no site e compre sua cópia original


Você realmente conhece Orientação a Objetos?

Nesta obra explicamos, passo a passo, e com muitos


exemplos práticos, como entender melhor cada conceito da
POO, incluindo também padrões de projeto e construção de
frameworks.

Veja mais sobre este livro aqui:

http://www.danielschmitz.com.br/dominando-orientacao-objetos.html
Dica

Use o sumário do arquivo PDF para navegar


entre os tópicos desta obra
Prefácio
O Desenvolvimento Mobile ganha novos adeptos a cada dia, e com o surgimento de
dezenas de dispositivos móveis no mercado, caracterizados principalmente pelos tablets e
celulares, o mobile ganha força como uma ótima área para investimento. A Adobe, ciente
deste crescimento, vem através dos últimos três anos formando a base para o que
podemos chamar de desenvolvimento mobile através do uso do Flex, e de sua IDE Flash
Builder.

Esta base começou com grandes mudanças na versão 4 do framework, trazendo


principalmente o conceito de Skins e a separação completa entre visualização e lógica.
Nesta nova versão, a 4.6, a Adobe traz mais componentes para os projetos mobile e
melhora a performance em geral. Além disso, traz a tão esperada compatibilidade entre
iphone, ipad, android e blackberry. A idéia é desenvolver uma aplicação única para todos os
tipos de dispositivo existentes.

Nesta obra, concentramos nosso foco em criar sistemas para os dispositivos mobile, do qual
podemos inserir/alterar dados e trabalhar com o básico do que um mobile pode nos
fornecer.
Convenções utilizadas nesta obra

 Informa uma dica ou observação ao leitor

 Indica que será exibido um arquivo

// ......... Indica que existe código fonte, mas não será exibido porque não é relevante
naquele momento.

Código em Negrito Indica alterações no código fonte, como por exemplo, uma nova
propriedade adicionada a um componente.

, ,  até   São referências ao código realizadas para um melhor entendimento.


Sempre que houver estas referências existirá uma explicação após o código

Sempre que encontrar um texto COMO ESTE, estamos referenciando algum dado na tela,
como o nome do projeto ou um botão que deve ser clicado.

Suporte

Acesse www.danielschmitz.com.br para conferir as últimas novidades do livro, capítulos


extra, código fonte, etc. Você também pode enviar um email para o autor, caso tenha
dúvidas sobre esta obra.

Autor: Daniel Pace Schmitz


Site: www.danielschmitz.com.br
Email para suporte: suporte@danielschmitz.com.br
Twitter: @Daniel_Schmitz
SUMÁRIO
1 Introdução ..................................................................................................................... 11

1.1 O que é o framework Flex? .................................................................................. 11

1.2 O que é MXML? .................................................................................................... 12

1.3 O que é Action Script? .......................................................................................... 13

1.4 Como o Flex Mobile funciona? ............................................................................. 13

1.5 Instalação do Adobe Flash Builder 4.6 ................................................................. 14

1.6 Como esta obra está dividida ............................................................................... 15

2 Conhecendo o Flex Mobile ............................................................................................ 16

2.1.1 Perspective ....................................................................................................... 17

2.1.2 Workspace ....................................................................................................... 17

2.1.3 Editor................................................................................................................ 18

2.1.4 Project .............................................................................................................. 18

2.2 Tipos de projetos no Flash Builder 4.6 ................................................................. 18

2.3 Criando o primeiro projeto Flex Mobile ............................................................... 20

2.4 Configurando e executando o projeto Mobile ..................................................... 23

2.5 Executando através de um outro dispositivo ....................................................... 24

2.6 Entendendo a arquitetura do Flex Mobile ........................................................... 26

2.7 Views .................................................................................................................... 27

2.8 Componentes recomendados .............................................................................. 28

2.9 Mais considerações para o framework Mobile .................................................... 29

3 Design e workflow do componente View ...................................................................... 30

3.1 Criando uma nova view ........................................................................................ 31

3.2 Navegando entre views ........................................................................................ 33


3.3 Parâmetros do pushView e popView ................................................................... 38

3.4 Outros métodos para navegação entre Views ..................................................... 38

3.5 Action Bar ............................................................................................................. 39

3.6 Definindo um botão voltar padrão ....................................................................... 40

3.7 Escondendo a Action Bar...................................................................................... 41

3.8 Utilizando ícones .................................................................................................. 42

3.9 Definindo menus para as views ............................................................................ 42

3.10 Criando uma aplicação mobile com TabBars (Sections) ....................................... 46

3.11 Configurando a disposição do dispositivo mobile (Retrato ou paisagem) ........... 48

3.12 Persistência de dados na View ............................................................................. 49

4 Componentes do Flex Mobile Framework ..................................................................... 51

4.1 ActionBar .............................................................................................................. 51

4.2 BusyIndicator ........................................................................................................ 51

4.3 TabbedViewNavigatorApplication ........................................................................ 52

4.4 ViewNavigatorApplication .................................................................................... 54

4.5 View ...................................................................................................................... 54

4.6 ViewMenu ............................................................................................................ 54

4.7 Button................................................................................................................... 54

4.8 CheckBox .............................................................................................................. 56

4.9 Group.................................................................................................................... 56

4.10 Image .................................................................................................................... 57

4.11 Label ..................................................................................................................... 58

4.12 List ........................................................................................................................ 58

4.13 RadioButton ......................................................................................................... 59

4.14 RadioButtonGroup ............................................................................................... 59


4.15 TextInput .............................................................................................................. 60

4.16 SplitViewNavigator ............................................................................................... 60

4.17 CallOutButton ....................................................................................................... 61

4.18 SpinnerList e DateSpinner .................................................................................... 62

4.19 ToogleSwitch ........................................................................................................ 63

4.20 Alert ...................................................................................................................... 63

5 Trabalhando com listas .................................................................................................. 65

5.1 O evento change .................................................................................................. 65

5.2 Item Renderers no List ......................................................................................... 67

5.3 Conhecendo o IconItemRenderer ........................................................................ 68

6 Criando a aplicação FlexTasks ........................................................................................ 72

6.1 Criando o projeto ................................................................................................. 72

6.2 Incluindo ícones.................................................................................................... 75

6.3 Persistência de dados ........................................................................................... 76

7 Flex Mobile com Swiz Framework ................................................................................. 94

7.1 O que é SWIZ? ...................................................................................................... 94

7.2 Download do Swiz ................................................................................................ 94

7.3 Instalação do Swiz no projeto .............................................................................. 94

7.4 Criando uma lista de cidades ............................................................................... 96

7.5 Criando um filtro ................................................................................................ 100

7.6 Refatorando a lista de estados ........................................................................... 104

7.7 Porque usar SWIZ? ............................................................................................. 110

8 Banco de dados SQLite ................................................................................................ 115

8.1 Conectando no banco de dados ......................................................................... 116

8.2 Acesso ao banco de dados ................................................................................. 118


8.3 Inserindo dados .................................................................................................. 119

8.4 Retornando dados tipados ................................................................................. 123

8.5 Modo síncrono ou assíncrono ............................................................................ 124

9 Mobile com SQLite e Swiz ............................................................................................ 125

9.1 Configurações iniciais ......................................................................................... 126

9.2 Criando o banco de dados .................................................................................. 127

9.3 Cadastrando estados .......................................................................................... 130

9.4 Cadastrando cidades .......................................................................................... 135

9.5 Finalizando o sistema ......................................................................................... 141

10 Interação com o dispositivo mobile ........................................................................ 144

10.1 StageWebView (Browser)................................................................................... 145

10.2 Touch .................................................................................................................. 147

10.3 Gestures (Gestos) ............................................................................................... 150

10.3.1 Zoom .......................................................................................................... 150

10.3.2 Swipe ......................................................................................................... 152

10.4 Pan...................................................................................................................... 155

10.5 Rotate ................................................................................................................. 155

10.6 Câmera ............................................................................................................... 156

10.7 Acesso à câmera ................................................................................................. 156

10.8 Tirar uma foto nativamente ............................................................................... 158

10.9 Acelerômetro ..................................................................................................... 158

10.10 GPS ................................................................................................................. 160


1 Introdução
Em 2011, o framework Adobe Flex 4.6 trouxe para o desenvolvimento RIA a possibilidade
de criar aplicações para dispositivos móveis, que vamos chamar de “Mobile”, que são os
celulares e tablets.

Ao mesmo tempo, vimos uma bruta ascensão de tais dispositivos, cada vez mais baratos e
populares. Mesmo que aqui no Brasil o processo de popularização dos dispositivos mobile
seja mais lento e caro, chegará um momento em que a venda destes produtos irá superar a
venda dos NetBooks, gerando assim uma demanda muito grande de software para esta
arquitetura.

Falando em arquitetura, os dispositivos mobile são mais fracos em processamento e


memória, e por isso necessitam de um tratamento diferenciado em relação às aplicações
desktop. Ou seja, temos que criar aplicações mobile com o pensamento na performance, e
não podemos criar uma aplicação que seja usada tanto no desktop quanto no mobile.

Felizmente o framework Flex mobile trouxe um bom conjunto de idéias e componentes que
exploram a necessidade de obter a melhor performance possível, na qual veremos ao longo
desta obra.

1.1 O que é o framework Flex?


Provavelmente você já conhece o Adobe Flex, pelo menos no seu conceito mais simples: ele
é um framework para criar aplicações web, desktop e mobile. Mas para que possamos
explicar melhor todos os conceitos ligados ao Flex, vamos fazer uma pequena retrospectiva
sobre o ciclo de vida do Adobe Flex.

Podemos dizer que o Flex começou a ser usado profissionalmente a partir de sua versão
2.0, lançado em junho de 2006. Perceba que o framework está caminhando para quase seis
anos de vida, o que garante muita maturidade no framework como um todo. Nas suas
versões iniciais, o Flex era usado para criar aplicações que funcionariam em um navegador
web, sem uso de HTML ou Javascript, usando o plugin do Flash Player para executar toda a
aplicação. Ou seja, o plugin Flash Player que é usado até hoje para criar aqueles banners de
propaganda com efeitos “legais”, também estava sendo reaproveitando para criar sistemas
web.
Quando dizemos um “sistema web”, afirmamos que o Flex é usado para criar aplicações,
que envolvem menus, formulários, datagrids etc, que manipulam dados e exibem
informações para o usuário.

Na atual versão, o framework Flex é usado para criar aplicações para a web, para o desktop
e para o mobile. Nosso foco nesta obra é a criação de sistemas para o mobile.

1.2 O que é MXML?


MXML é uma linguagem de marcação de texto, baseada no XML, e de alguma forma
semelhante ao HTML. Se você já usou HTML, criando aqueles divs, tables etc., ficará a
vontade com MXML.

Se você nunca usou HTML, a IDE Flash Builder possui um modo chamado Design, no qual
você pode arrastar os componentes para a sua interface, montando ela como um todo
(semelhante ao Delphi, ou Windows Forms .Net).

Um exemplo básico de código MXML é exibido a seguir:


<s:Label x="9" y="140" text="Resultado:" width="186"/>

Neste exemplo, criamos um Label que possui coordenadas x e y dentro de uma aplicação,
uma largura (width) de 186 pixels e o texto “Resultado”. Assim como no HTML, podem-se
adicionar componentes dentro de componentes e assim criar uma estrutura mais
complexa, por exemplo:
<s:Group x="12" y="11" width="207" height="201">
<s:TextInput x="9" y="11" width="186" id="Operador1"/>
<s:ComboBox x="9" y="39" openOnInput="true" width="186"/>
<s:TextInput x="9" y="70" width="186" id="Operador2"/>
<s:TextInput x="9" y="167" width="186" id="Resultado"/>
<s:Label x="9" y="140" text="Resultado:" width="186"/>
<s:Button x="9" y="97" label="Executar" width="186" />
</s:Group>

Neste código, criamos um grupo de componentes, posicionando cada um no eixo x-y.


Poderíamos também criar componentes lado a lado, tanto horizontalmente quanto
verticalmente.

O MXML existe porque é muito mais fácil criar uma interface em uma linguagem declarativa
(como o XML) do que imperativa (como o Action Script). Isso quer dizer que tudo que
fazemos em MXML (ou quase tudo) pode ser feito com Action Script, mas desenhar
interfaces é algo extremamente frustrante. Para termos uma idéia, o código anterior de 8
linha vai para no mínimo 100 linhas em Action Script.

1.3 O que é Action Script?


Action Script é uma linguagem de programação, orientada a objetos, baseada no padrão
ECMAScript3, o que garante certa semelhança às linguagens derivadas do C, como o C#,
PHP, Java e Java Script. A atual versão do Action Script é a 3, com um bom suporte a
orientação a objetos (mas pode melhorar...), e uma ótima API, vinda do Flash Player ou da
máquina virtual do Adobe Air.

O que podemos já saber, e isso é muito importante, é que todo código MXML relativo aos
componentes torna-se código Action Script 3. Isso é, o <s:label /> que criamos no MXML, na
verdade é uma classe em ActionScript. O compilador faz esta conversão no momento em
que estamos compilando o projeto.

Fazendo uma analogia ao desenvolvimento web tradicional, a dobradinha


MXML+ActionScript pode ser comparada com o HTML+Java Script. Você pode imaginar
como seria difícil criar divs, tables e forms apenas com Java script e também como é fácil
trabalhar com o HTML, sabendo que um <h2> é um título e um <p> parágrafo. Uma
diferença positiva em relação ao MXML é que o que você desenhar é o que será visto
independente do navegador ou do sistema operacional. Todos conhecem a guerra entre os
navegadores e cada um com a sua própria engine de renderização. No caso do Flex, como a
engine é a mesma, o Flash Player, você terá o mesmo resultado independente se estiver
usando Internet Explorer ou Firefox.

1.4 Como o Flex Mobile funciona?


Há alguns anos a Adobe criou o AIR – Adobe Integrated Runtime – que é uma máquina
virtual usada para executar aplicativos. Funciona com muita similaridade ao JVM, a
máquina virtual Java.

Isso significa que você deverá criar aplicações para serem executadas no AIR e não mais no
navegador Web. Ou seja, quando você programa para Adobe Air, você não se preocupa a
sua aplicação vai funcionar para Windows, Mac ou Linux.

Este conceito é idêntico ao desenvolvimento mobile. Você irá criar o seu programa para
que possa funcionar em uma máquina virtual (AIR) que estará instalada no celular ou tablet
do cliente. Desta forma, você não necessita saber qual o tipo ou a versão do celular na qual
está criando o sistema. Basta apenas saber se o dispositivo possui o Adobe Air instalado.

Ou seja, já podemos perceber que uma aplicação mobile é na verdade uma aplicação Adobe
Air, só que com alguns detalhes a mais, no qual veremos ao longo desta obra. Para certificar
que o seu dispositivo mobile está compatível com o Adobe AIR e com o Flex Mobile, acesse
1
este endereço . Você instala o Adobe AIR nos respectivos “markets” de acordo com o
sistema operacional do seu celular.

1.5 Instalação do Adobe Flash Builder 4.6


O Flex é composto por duas partes distintas: O SDK, que é o kit de desenvolvimento de
software, open source e gratuito, e a IDE, que é a ferramenta de desenvolvimento (que
inclusive já contém o SDK) e tem um custo, mas pode também ser adquirida gratuitamente
para projetos não comerciais. Nesta obra estaremos utilizando a IDE Adobe Flash Builder
4.6, que instala tudo que precisamos deixando o Flex pronto para ser utilizado.
2
Para realizar o download do Flash Builder 4.6 acesse este link . Na próxima tela, escolha a
versão de acordo com o Sistema Operacional, e clique em Download Now. Faça o login ou
crie uma conta no site da Adobe, para que o download inicie. Você poderá fazer o
download do Akamai Download Manager para que ele se encarregue de gerenciar o
download, ou então baixar os arquivos diretamente.

Após o download terminar, execute o arquivo de instalação e aguarde a preparação dos


arquivos até chegar na tela inicial de instalação, que contém o contrato de licença. Clique
em “Aceitar”. Na próxima tela, você deve digitar o número de série ou então selecionar a
versão de avaliação. Selecione a opção desejada, depois o idioma e então clique em
“Avançar”. Na próxima tela, surgem os produtos que serão instalados, bem como o local.
Você pode deixar tudo como padrão e clicar em “Instalar”. Para garantir que os plugins do
flash player em modo debug sejam instalados, feche todos os navegadores web que
estejam abertos. Aguarde a conclusão da instalação.

1
http://www.adobe.com/flashplatform/certified_devices/
2

http://www.adobe.com/cfusion/tdrc/thankyou_2.0.cfm?product=flash_builder&loc=pt_br
O Flash Builder 4.6 não é gratuito, ele é pago, mas existem versões de avaliação por 60 dias,
3
e versões para estudantes e desempregados (Ainda está na versão 4.5). Você pode usar o
Flash Builder 4.6 para aprender Flex, e decidir pela compra da IDE somente quando estiver
confortável quanto ao seu uso. O framework Flex SDK 4.6 é open source, isto é, pode-se
compilar uma aplicação inteira em Flex, somente usando a linha de comando do Windows
(antigo DOS) ou o console do Mac/Linux, escrevendo o código diretamente em um editor de
textos comum. Mas este não é o foco desta obra, iremos usar constantemente o Flash
Builder 4.6 para apresentar os benefícios do Framework Flex juntamente com a sua IDE.

1.6 Como esta obra está dividida


Podemos considerar que esta obra divide-se em duas partes bastante específicas. A
primeira possui toda a teoria necessária para que possamos entender como o framework
Flex Mobile funciona. Diferentemente dos livros anteriores, onde podíamos criar um
projeto e já começar a criar aplicações, no mobile precisamos entender alguns conceitos
antes de partir a aplicação. Isso não significa que vamos ver apenas teoria, veremos teoria
com diversos exemplos. A segunda parte aborda o uso da tecnologia para acessar dados e
informações do dispositivo mobile, contendo exemplos práticos.

3
https://freeriatools.adobe.com/
2 Conhecendo o Flex Mobile
Após a instalação do Flash Builder 4.6, execute-o, e após o seu carregamento, você verá
uma tela conforme a Figura 2.1. No centro, temos a aba “Start Page”, com diversos links
para o aprendizado Flex, em inglês.

Figura 2.1- Tela inicial do Flash Builder 4.6

O termo workbench é usado para ilustrar todos os recursos de visualização do Flash Builder
4.6 relativos a suas configurações e janelas. Como o Flash Builder 4.6 foi construído
utilizando a plataforma Eclipse, existem muitos conceitos que devem ser entendidos para
que possamos extrair o máximo de produtividade da ferramenta.
2.1.1 Perspective

Todas as janelas internas do Flash Builder 4.6 podem ser alteradas de tamanho, bem como
alteradas de posição. Podem estar ocultas ou não. Como existem muitas janelas,
normalmente organizadas em abas, o Eclipse criou um conceito chamado Perspective, que é
a perspectiva das janelas de acordo com o contexto da aplicação.

A perspectiva é exibida no canto superior direito da aplicação, a inicialmente vem com o


padrão “Flash”. Vamos então alterar a perspectiva, navegando até o menu “Window > Open
Perspective > Flash Debug”. Veja que, ao selecionar esta perspectiva, a organização das
janelas muda completamente, incluindo novas abas e sumindo com outras. Para voltar a
perspectiva “Flash”, você poderá usar o menu “Window > Open Perspective” ou então usar
os botões no canto superior direito do Flash Builder 4.6.

Você pode criar novas perspectivas e alterá-las facilmente na barra de ferramentas de


perspectivas.

 Você pode clicar com o botão direito do mouse na barra de perspectiva e retirar o item
“Show Text”, deixando somente o ícone para ilustrar as perspectivas recentemente abertas.

2.1.2 Workspace

O conceito de workspace é diferente de workbench. Um workspace é caracterizado através


de um arquivo de configuração que altera praticamente tudo dentro do Flash Builder 4.6.
Apesar de pouco usado, este conceito pode ser útil em determinadas situações
relacionadas à configuração do eclipse.

Por exemplo, suponha que você tenha dois clientes, e um deles é um projeto Flex+PHP,
com vários projetos abertos no Flash Builder 4.6. Outro cliente já utiliza Flex+Java,
contendo mais alguns projetos relacionados a Java. Ter todos estes projetos abertos em
somente uma instância do Flash Builder 4.6 trariam confusão na manipulação dos mesmos,
além de prejudicar a performance. Para isso, você cria workspaces onde cada um deles será
destinado a um cliente, ou a algum tipo de projeto.

Para alterar o Workspace, você pode acessar o menu “File > Switch Workspace”.
2.1.3 Editor

Um editor é responsável em editar arquivos do seu projeto, mas com a particularidade de


possuir recursos extras para cada tipo de arquivo. Por exemplo, o editor de arquivos MXML
possui o modo Source e o modo Design. Já o editor de arquivos CSS apresenta outras
particularidades distintas. O mesmo vale para arquivos PHP, Java, Action Script.

2.1.4 Project

Um projeto é a reunião de vários arquivos de diversos tipos e diversos editores, com o


propósito de representar a sua aplicação, seja ela web, desktop ou mobile. Veja que uma
aplicação pode conter um ou mais projetos, e que projetos podem ser compartilhados
entre aplicações.

Por exemplo, você pode criar um projeto que contém somente componentes
personalizados, e pode criar vários projetos que utilizam estes componentes.

2.2 Tipos de projetos no Flash Builder 4.6

Existem duas formas para criar um projeto Flex no Flash Builder 4.6. A primeira delas é ir
até o menu “File” e depois “New”. A segunda forma, mais usada, é clicar com o botão
direito do mouse na janela “Package Explorer” e escolher o menu “New”.

 Botão direito na janela “Package Explorer” mostra um menu que pode variar de acordo
com o item selecionado. Quando você selecionar um projeto, perceberá que o menu será
alterado.

Ao criar um novo projeto (Figura 2.2), temos a disposição sete tipos de projeto diferentes,
veja:

 Flex Project: Cria um projeto Flex, que pode ser executado na Web ou no Desktop,
e também pode conectar-se a diversos tipos de servidor, como ColdFusion, Java,
PHP.
 Flex Library Project: Cria uma biblioteca de componentes para uso no Flex. Esta
biblioteca pode, por exemplo, conter componentes que são compatíveis com as
versões Web, Desktop ou Mobile.
 Flex Mobile Project: Uma das grandes novidades desta versão, agora é possível
criar projetos totalmente customizados para dispositivos mobile.
 Action Script Project: Pode-se criar um projeto totalmente em Action Script. Neste
tipo de projeto, não são usados os arquivos MXML para o desenho da aplicação, e
não há o recurso “Design” de formulários. Este tipo de projeto é mais usado para a
criação de jogos utilizando a plataforma Flex.
 Action Script Moibile Project: Possui o mesmo conceito do Action Script Project,
mas otimizado para os dispositivos mobile.
 Flash Professional Project: Cria um projeto Flash, que é diferente do Flex. Este tipo
de projeto não será abordado nesta obra.
 Flash Catalyst Compatible Project: Cria um projeto que é compatível com o Flash
Catalyst.

Figura 2.2 - Criando um novo projeto Flex


2.3 Criando o primeiro projeto Flex Mobile
O projeto Mobile é criado através do menu File > New > Flex Mobile Project. Surge então o
assistente, conforme a Figura 2.3, onde poderemos inserir um nome para o projeto, o local
onde o projeto será criado, e a versão do SDK do Flex que será usada.

Figura 2.3 - Criando o projeto Mobile

No nome de projeto, coloque HelloWorld, deixe o caminho padrão do projeto e a versão


padrão do SDK. Clique em Next, para acessar a segunda tela do assistente - Figura 2.4, que
é uma novidade para os desenvolvedores Flex. Nesta tela, estaremos configurando qual a
plataforma da aplicação.

Após escolher a plataforma, existem três abas para a configuração do projeto mobile para a
plataforma. A primeira aba, chamada de Application Type, define como a aplicação
será desenhada inicialmente. Existem três formas distintas, que veremos com mais detalhes
no decorrer da obra. Por enquanto, vamos deixar o item View-Based Application
selecionado. No campo Initial view Title, vamos deixar o padrão, HomeView.
Figura 2.4 - Editando as configurações iniciais do projeto Flex Mobile

A segunda aba configura as permissões que a aplicação terá com o dispositivo mobile. No
caso do Google Android, existem algumas permissões que podem ser selecionadas,
tais como READ_PHONE_STATE, CAMERA, RECORD_AUDIO, entre outros. A terceira
aba, chamada de Plataform Settings, realiza algumas configurações extras, mas isso
depende de cada dispositivo. No Google Android, não há mais nada para ser
configurado.

Após estas três abas, existem mais algumas configurações na caixa Application
Settings. Dentre elas temos:
 Automatically reorient: Determina se a aplicação deve “girar” caso o dispositivo
mobile gire.
 Full Screen: Determina se a aplicação será executada no modo Full Screen – tela
cheia, onde a barra de status e de navegação não serão exibidas.
 Automatically scale : Determina se a aplicação terá um tratamento especial para a
diferença entre os diversos tamanhos de dispositivo mobile, possibilitando assim
que seja criado componentes com diferentes resoluções para cada tipo de
dispositivo.

Destas três opções, deixe somente a primeira marcada, relacionada a reorientação


automática. Não é preciso seguir para os próximos passos do assistente. Clique no botão
Finish para que possamos ver a criação da aplicação no Package Explorer.

Com o projeto criado, podemos ver no Package Explorer os arquivos iniciais da aplicação,
conforme a Figura 2.5.

Figura 2.5 - Projeto HelloWorld


2.4 Configurando e executando o projeto Mobile
Após a criação do projeto, podemos executá-lo. Nesta obra, estaremos apenas simulando a
execução da aplicação em um dispositivo pré configurado. Precisamos configurar um
dispositivo para que o tamanho da aplicação e seus parâmetros de configuração sejam
devidamente informados.

Execute a aplicação clicando no botão Run: . Como é a primeira vez que a aplicação está
sendo executada, e ainda não existe uma configuração estabelecida, surge a janela Run
Configurations, conforme a Figura 2.6.

Figura 2.6 - Configurando um dispositivo para executar a aplicação

Em Launch Method, escolha o item On desktop, e escolha um dispositivo para a


simulação. Depois, clique em Apply e em Run. A aplicação mobile será simulada de
acordo com o dispositivo escolhido, de acordo com a Figura 2.7.
Figura 2.7 - Simulação da aplicação no dispositivo

2.5 Executando através de um outro dispositivo


Suponha agora que você deseja executar a aplicação no Motorola Xoom. Para isso, vá
até o menu Run, e escolha o item Run Configurations. Você verá, conforme a Figura
2.8, que existe a configuração HelloWorld, e o botão New Launch
configuration. Clique neste botão e configure os seguintes parâmetros. Em Name,
coloque HelloWorldWithXoom. Em Project, escolha o projeto HelloWorld,
utilizando o botão Browse. Escolha On desktop em Launch Method e depois
escolha o dispositivo Motorola XOOM. Clique em Apply e depois em Run, e você verá
uma tela muito maior que a primeira configuração realizada.
Figura 2.8 - Adicionando uma nova configuração para executar o projeto mobile

Após adicionar estas duas configurações de execução, você pode executá-las conforme o
menu Run, exibido na Figura 2.9.
Figura 2.9 - Execução da aplicação depende do dispositivo

2.6 Entendendo a arquitetura do Flex Mobile


Neste capítulo começaremos a abordar as principais diferenças entre uma aplicação flex
mobile e uma aplicação flex web/desktop. O primeiro conceito que precisamos entender no
mobile é: menos é mais. Isto é, no desenvolvimento mobile, estamos sempre optando pela
simplicidade tanto nas telas quanto na programação realizada, pois a arquitetura mobile
exige isso.

Por quê? A arquitetura mobile exige este comportamento porque a tela onde as
informações são exibidas é muito menor do que uma tela exibida na web/desktop, e os
recursos de hardware para o mobile são inferiores aos recursos de uma arquitetura
web/desktop. Ou seja, temos uma tela menor para dispor informações e um hardware mais
lento.

Felizmente a Adobe teve uma preocupação muito grande nestas limitações, e restringiu o
seu framework (entenda como uma limitação nos componentes disponíveis) para que a
aplicação funcionasse de forma satisfatória. Além disso, criou um conceito simples para que
possamos criar cada tela da aplicação mobile de forma rápida e fácil.
2.7 Views
Se você reparar na Figura 2.5, verá no projeto um package com o nome views, além de
um arquivo MXML com o nome HelloWorldHomeView.mxml. Na arquitetura Flex
Mobile, a Adobe introduziu o conceito de Views, que pode ser considerada como uma tela
que representa algum tipo de informação no dispositivo mobile.

 Nota do autor: A palavra “view” não será traduzida para “visão”.

Cada view deve representar somente um tipo de informação, e uma aplicação mobile é
formada por diversas views. Na Figura 2.10 temos o exemplo de duas views diferentes. A
primeira delas exibe uma lista de pessoas, e a segunda é exibida quando escolhemos o item
Lauren.

Figura 2.10 - Duas views diferentes

Resumindo, para criar uma aplicação mobile utilizando o framework Flex, você precisa criar
views e prover a comunicação entre elas. Este conceito é um pouco diferente do
desenvolvimento web/desktop, onde você tinha uma tela “vazia” e precisava criar, do zero,
as telas do sistema.
2.8 Componentes recomendados
Nem todos os componentes do framework Flex podem ser usados no mobile. Isso deve-se a
restrição ligada a performance e às Skins de cada tipo de componente. Quando estamos no
ambiente mobile, o Flex sabe aplicar skins diferentes aos componentes que o mobile
suporta (isso acontece através do tema “mobile.swc”). Os componentes MX, do Flex 3,
também não podem ser usados, com exceção dos componentes gráficos e do mx:spacer
(mas não recomendamos, já que existe o s:spacer).

A seguir, exibimos uma lista de componentes que podem ser utilizados na aplicação mobile:

 Spark ActionBar  SparkDateSpinner


 Spark BusyIndicator  Spark ToggleSwitch
 Spark TabbedViewNavigator  Spark Group
Application  Spark HGroup / VGroup
 Spark TabbedViewNavigator  Spark TileGroup
 Spark View  Spark Image / BitmapImage
 Spark ViewMenu  Spark Label
 Spark ViewNavigator  Spark List
 Spark ViewNavigatorApplication  Spark RadioButton
 Spark Button  Spark RadioButtonGroup
 Spark CheckBox  Spark SkinnableContainer
 Spark DataGroup  Spark Scroller
 Spark SplitViewNavigator  Spark TextArea
 Sapr kCallOut Button  Spark TextInput
 Spark SpinnerList

Para todos os outros componentes, o seu uso é problemático. Para gráficos MX, o seu uso
pode gerar problemas de performance, o que pode ser resolvido em versões futuras.
2.9 Mais considerações para o framework Mobile
Além da restrição dos componentes, existem algumas considerações que devemos estar
atentos, para que possamos criar aplicações com performance.

Item Renderers

Se possível, escreva Item Renderers em Action Script. Todo o código MXML é traduzido para
Action Script, e se você escrever um item renderer em action script nativamente, ganhará
performance. Você verá mais sobre item renderers no Capítulo 5.2. Além disso, existem
dois item renderers que são otimizados para o mobile. São eles:

 LabelItemRenderer
 IconItemRenderer

Sempre que possível, use estes item renderers, que podem ser em MXML.

Skins

O conceito de Skin, vindo do Flex 4, também está presente no Flex Mobile. Por exemplo, o
Spark Button no framework Mobile é o mesmo Spark Button do desktop (funcionalidades),
mas a sua Skin é diferente porque quando criamos um projeto Mobile, estamos aplicando o
tema “mobile.swc” no projeto. Se você for criar um novo tema com novas Skins, a
recomendação da Adobe é criar a Skin nativamente com Action Script, e usar somente
gráficos FXG (vetorial), ao invés de bitmap.

Uso do TLF

O TLF – Text Layout Framework - é uma renderização especial para o texto, possibilitando
suporte a idiomas (chinês, por exemplo), textos na vertical, entre outros. A Adobe
recomenda que utilize os componentes Spark Label, Spark TextInput e Spark TextArea para
evitar o uso do TLF e conseqüentemente ter problemas de performance.
3 Design e workflow do componente View
Neste capítulo, veremos como criar uma aplicação mobile usando o conceito aprendido no
capítulo 2.7, que é a View. Uma view é um componente do framework Flex, assim como um
Panel ou um TitleWindow, e representa a tela do dispositivo mobile, composta basicamente
de uma área destinada ao cabeçalho da aplicação, uma área destinada ao conteúdo e outra
destinada ao rodapé.

As áreas: cabeçalho, conteúdo e rodapé possuem seus respectivos nomes em inglês, e não
traduziremos estes nomes para não dificultar o aprendizado. Basicamente, uma view tem
uma ActionBar (Cabeçalho), um Content Area (Conteúdo) e um TabBar (Rodapé).

Figura 3.1 - Esquema básico de uma view


Na Figura 3.1, temos um exemplo de view com as três áreas distintas. Para que possamos
entender melhor o conceito de view, vamos retornar ao projeto HelloWorld e abrir os
dois arquivos MXML que foram criados: HelloWorld.mxml e HelloWorldHome
View.mxml.

/HelloWorld/src/HelloWorld.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:ViewNavigatorApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
firstView="views.HelloWorldHomeView"
>

</s:ViewNavigatorApplication>

/HelloWorld/src/views/HelloWorldHomeView.mxml
<?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="HomeView">

</s:View>

Apesar dos dois arquivos mxml não conterem nenhum conteúdo, já podemos observar
algumas particularidades na estrutura da aplicação. A primeira delas é que o arquivo
principal do projeto, o HelloWorld.mxml, possui o componente ViewNavigator
Application. Ou seja, ele não é um Spark Application (Web) ou um
WindowedApplication (Air - Desktop).

Além disso, o ViewNavigatorApplication possui a propriedade firstView, que


indica a primeira view a ser carregada. A primeira view, que é o arquivo
HelloWorldHomeView.mxml, também não contém muita informação, apenas a
propriedade title que determina o título da ActionBar (Cabeçalho) daquela view.

3.1 Criando uma nova view


Criar uma nova view significa criar um novo componente MXML, que herda do componente
Spark View. Clique com o botão direito do mouse no package views, e selecione New >
MXML Component. Crie o componente de acordo com a Figura 3.2, onde colocamos o
nome HelloWorldAgain e criamos o componente baseado no componente
spark.components.View.
Figura 3.2 - Criando uma nova View

Após criar a nova View, você terá dois arquivos MXML no package views. Vamos aproveitar
e criar mais uma View, com o nome de “HelloWorldDolly”, resultando no projeto conforme
a Figura 2.1.
Figura 3.3 - Projeto mobile com 3 views

3.2 Navegando entre views


Até o momento temos uma aplicação com três views, e a view HelloWorldHomeView é a
primeira a ser carregada. Como faço então para carregar outras views? O Framework Flex
disponibiliza um sistema baseado em empilhamento de views.

Um empilhamento de views significa que, quando você navegar para a próxima view, você
estará na verdade colocando uma view sobre a outra, como se fosse aquele velho exemplo
dos pratos (pilhas, stacks, você deve lembrar disto da faculdade, espero). Neste momento,
você deve lembrar daqueles comandos push e pop de um array, pois o conceito é o
mesmo aqui.

Para exemplificar, vamos criar um botão que irá carregar a tela HelloWorldAgain. Para fazer
isso, utilize o seguinte código:

 /HelloWorld/src/views/HelloWorldHomeView.mxml
<?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="HomeView">

<s:layout>
<s:VerticalLayout
paddingTop="10"
paddingLeft="10"
paddingRight="10"/>
</s:layout>

<s:Button label="Ir para outra view"


width="100%">
<s:click>
<![CDATA[
navigator.pushView(views.HelloWorldAgain);
]]>
</s:click>
</s:Button>

</s:View>

Em , definimos que o conteúdo da view terá o layout vertical, e definimos alguns


paddings para que a view fique melhor enquadrada na aplicação. Em  criamos um botão,
e definimos através do evento click () uma ação. Esta ação, em , usa a propriedade
navigator da view para que possamos executar o método pushView, repassando
como parâmetro qual a view que será carregada.

Diferente das aplicações web/desktop, aqui não usamos (para acessar novas views) os
métodos addChild ou addComponent dos containers do framework.

O resultado do código acima é representado pelas imagens a seguir:


Quando o usuário clica no botão Ir para outra view, é feita uma transição da view
atual para a view HelloWorldAgain. O efeito de transição e a troca de conteúdo é feita
automaticamente pelo framework.

O que temos agora na aplicação é que a view HelloWorldAgain está “por cima” da
view HelloWorldHomeView, veja:

HelloWorld.mxml

HelloWorldAgain.mxml

pushView()

HelloWorldHomeView.mxml

Vamos novamente usar o pushView para adicionar mais uma view, só que agora na view
HelloWorldAgain, veja:

/HelloWorld/src/views/HelloWorldAgain.mxml
<?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="HelloWorldAgain">

<s:layout>
<s:VerticalLayout
paddingTop="10" paddingLeft="10"
paddingRight="10"/>
</s:layout>
<fx:Script>
<![CDATA[
protected function
OnbtnClick(event:MouseEvent):void
{
this.navigator.pushView(views.HelloWorldDolly);
}
]]>
</fx:Script>
<s:Button label="Hello Dolly !!" width="100%" height="200"
click="OnbtnClick(event)"
>
</s:Button>
</s:View>

Agora temos a seguinte situação:

HelloWorld.mxml

HelloWorldDolly.mxml

pushView()

HelloWorldAgain.mxml

HelloWorldHomeView.mxml

Temos três views, uma sobre a outra, sendo que a view que está sendo exibida para o
usuário é a HelloWorldDolly. Nesta view, vamos criar o botão “voltar”. Este botão irá
voltar para a view anterior, e não carregar uma nova view. Ou seja, iremos retirar a view
que está sendo visualizada para recarregar a view anterior. Para isso, usamos o método
popView(), veja:

/HelloWorld/src/views/HelloWorldDolly.mxml
<?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="HelloWorldDolly">

<s:layout>
<s:VerticalLayout
paddingTop="10"
paddingLeft="10"
paddingRight="10"/>
</s:layout>

<s:Label text="Hello Dolly!!"/>

<s:Button label="Voltar">
<s:click>
<![CDATA[
this.navigator.popView();
]]>
</s:click>
</s:Button>

</s:View>

Além das configurações normais da view, temos em , o método popView(), que irá
retirar a view corrente e recarregar a view anterior, realizando o efeito inverso da animação
(da direita para a esquerda).

Através destes dois métodos, pushView e popView, você consegue adicionar/retirar


telas (views) da sua aplicação, realizando a interação com o usuário.

Veja que, mesmo comentando que uma view fica por cima da outra, simulando uma pilha
de views, isso não ocorre realmente. Por uma simples questão de performance, somente
uma tela é carregada na memória por vez, mesmo que a impressão seja que existam telas
uma por cima das outras. Este conceito é importante, pois você pode se confundir com o
componente ViewStack do Flex, no qual tínhamos vários componentes sendo que somente
um era visualizado, mas todos eles estavam na memória.
3.3 Parâmetros do pushView e popView
Vamos abordar agora, com mais cuidado, o método pushView. Se você reparou, ele
possui quatro parâmetros, no qual serão discutidos a seguir:

 class : É a classe que será carregada.


 data : É um objeto que pode ser repassado para a view a ser carregada. Este
objeto estará disponível na view através da propriedade data.
 context : É um objeto que determina o contexto que é repassado para a
propriedade navigator da view. A diferença em relação ao parâmetro data é que
o contexto é repassado para o navigator da view, e data é passada
diretamente para a view. O context pode ser acessado por todas as views.
 transition : Determina o efeito em que será realizado para carregar a próxima
view.

Já o popView possui apenas um parâmetro, que é a transição (efeito) para voltar a view
anterior, que quando omitida realiza uma transição padrão.

Como o framework Mobile integra-se ao dispositivo, quando o usuário executar o


comando voltar nativo do mobile será executado o comando popView.

3.4 Outros métodos para navegação entre Views


Além do pushView e do popView, temos mais alguns métodos relacionados a navegação
entre as views, conforme os itens a seguir:

 popToFirstView: remove todas as views da pilha de views, e exibe a primeira


view que foi carregada, geralmente definida pela propriedade firstView do
ViewNavigatorApplication.
 popAll: remove todas as views, e deixa a tela em branco.
 replaceView: Faz uma troca da view atual por outra view, ou seja, a nova view
não é adicionada “por cima” da outra, mas sim trocada.
3.5 Action Bar
Você já deve ter notado que, no desenvolvimento mobile, a view é um dos componentes
mais importantes, já que representa cada tela da aplicação. Na Figura 3.1, vimos também
que uma view possui um cabeçalho, que chamamos de Action Bar. O componente
ActionBar, que está automaticamente embutido na View, é um controle que possui três
áreas distintas para configuração, que são:

 Title area: Uma área central para adicionar um título a view. É definido
automaticamente pela propriedade title da view.
 Navigation area: Área à esquerda do title, destinado a inserir botões ou links de
navegação. É configurado através da propriedade <s:navigationContent>
 Action area: Área à direta do title, destinado a inserir botões de ação. É
configurado através da propriedade <s:actionContent>

A Adobe recomenda que você utilize botões na navigation area e action area e
use a propriedade title para configurar o título da title area, mas isso não significa
que você possa atribuir outros controles a estas áreas.

Por exemplo, você pode usar a propriedade titleContent para determinar o conteúdo da
área onde o título ficava, podendo, por exemplo, realizar a seguinte configuração:
<?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="Details">

<s:actionContent>

<s:Button label="Search">
<s:click>
<![CDATA[
navigator.pushView(views.HelloWorldAgain);
]]>
</s:click>
</s:Button>
</s:actionContent>

<s:titleContent>
<s:TextInput width="100%" prompt="Busca"/>
</s:titleContent>

</s:View>

O que resulta no seguinte resultado:

3.6 Definindo um botão voltar padrão


Caso haja a necessidade de definir uma área padrão para todas as views, podemos realizar
a mesma configuração, só que no mxml principal da aplicação, onde encontramos o
componente ViewNavigatorApplication, veja:

/HelloWorld/src/HelloWorld.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:ViewNavigatorApplication xmlns:fx="http://ns.adobe.com/mxml/2009"

xmlns:s="library://ns.adobe.com/flex/spark"

firstView="views.ViewWithActionBar">

<s:navigationContent>
<s:Button id="btnBack" label="Back">
<s:click>
<![CDATA[
this.navigator.popView();
]]>
</s:click>
</s:Button>
</s:navigationContent>
</s:ViewNavigatorApplication>
Neste exemplo, criamos o botão Back para executar a ação de popView. Este botão está
definido no navigation content, e estará presente em todas as views da aplicação
que não definirem um navigation content. Ou seja, o botão somente aparecerá nas
views que não implementarem a sua navigation area.

Cuidado para não confundir <s:NavigatorContent> com <s:navigationContent>

Não somente o navigation content pode ser “globalizado”, mas o title


content e o action content também.

3.7 Escondendo a Action Bar


Se você deseja esconder a ActionBar da sua view, pode usar a propriedade actionBarVisible,
conforme o exemplo a seguir.
<?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="Details">

<s:actionContent>
<s:Button label="close...">
<s:click>
<![CDATA[
this.actionBarVisible = false;
]]>
</s:click>
</s:Button>
</s:actionContent>

<s:titleContent>
<s:TextInput width="100%" prompt="Busca"/>
<s:Spacer width="10"/>
<s:Button label="Search">
<s:click>
<![CDATA[
navigator.pushView(views.HelloWorldAgain);
]]>
</s:click>
</s:Button>

</s:titleContent>

<s:navigationContent>

</s:navigationContent>
</s:View>

3.8 Utilizando ícones


A partir da versão 4.5 do framework Flex, os botões passam a aceitar ícones, através da
propriedade icon. Use o @Embed para adicionar o ícone diretamente no arquivo
compilado, veja:
<s:navigationContent>
<s:Button id="btnBack" label="Back"
icon="@Embed('assets/icons/back.png')">
<s:click>
<![CDATA[
this.navigator.popView();
]]>
</s:click>
</s:Button>
</s:navigationContent>

3.9 Definindo menus para as views


Para cada view criada, podemos definir um menu que será exibido na parte inferior do
dispositivo (podem haver alterações de acordo com o dispositivo). Este menu surge quando
usuário aciona o menu do dispositivo em questão, ou quando criamos um botão para fazer
executar esta tarefa.

Um menu não contém submenus, e não é possível criar tipos diferentes de componentes
além do componente ViewMenuItem. Os menus também não podem ser inseridos
globalmente na aplicação, pelo menos de uma forma fácil.

Para adicionar um menu na view, use a propriedade <s:viewMenuItems> e adicione


<s:ViewMenuItem>, conforme o exemplo a seguir:
<?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="Details">

<s:viewMenuItems>
<s:ViewMenuItem label="Novo"/>
<s:ViewMenuItem label="Copiar"/>
<s:ViewMenuItem label="Colar"/>
</s:viewMenuItems>

</s:View>

Para testar o menu, execute a aplicação e, como estamos simulando o dispositivo, acesse o
menu “Device” e clique em “Menu”, conforme a Figura 3.4.

Figura 3.4- Acessando o menu da aplicação

Pode-se adicionar ícones através da propriedade icon e capturar o evento click, para
realizar a ação desejada ao selecionar o item de menu, veja:
<?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="Details">
<s:actionContent>
<s:Button label="Search">
<s:click>
<![CDATA[
navigator.pushView(views.HelloWorldAgain);
]]>
</s:click>
</s:Button>
</s:actionContent>

<s:titleContent>
<s:TextInput id="txtBusca" width="100%" prompt="Busca"/>
</s:titleContent>

<s:navigationContent>

</s:navigationContent>

<s:viewMenuItems>
<s:ViewMenuItem label="Realizar Busca"

icon="@Embed('assets/icons/ic_menu_search.png')">
<s:click>
<![CDATA[
navigator.pushView(views.HelloWorldAgain);
]]>
</s:click>
</s:ViewMenuItem>
<s:ViewMenuItem label="Limpar tudo"

icon="@Embed('assets/icons/ic_menu_delete.png')">
<s:click>
<![CDATA[
this.txtBusca.text = "";
]]>
</s:click>
</s:ViewMenuItem>

<s:ViewMenuItem label="Novo"/>

<s:ViewMenuItem label="Copiar"/>
<s:ViewMenuItem label="Colar"/>

</s:viewMenuItems>

</s:View>
A configuração deste menu apresenta o resultado de acordo com a Figura 3.5.

Figura 3.5 - Menu com ícones e ações

Caso seja necessário abrir o menu sem usar o botão menu nativo do dispositivo mobile,
você pode usar o seguinte comando:
mx.core.FlexGlobals.topLevelApplication.viewMenuOpen=true
3.10 Criando uma aplicação mobile com TabBars (Sections)
Quando criamos o projeto HelloWorld, na Figura 2.4, tínhamos três tipos de projeto
mobile para escolher:

 Blank
 View-Baseade Application
 Tabbed Application

Nos projetos anteriores, utilizamos a aplicação baseada em Views, onde existia somente
uma única pilha de views. Agora vamos criar uma Tabbed Application, que consiste em criar
uma TabBar na parte inferior da aplicação e dividir a pilha de views em seções (sections).

Crie uma nova aplicação, chamada de HeloWorld2, e escolha o template Tabbed


Application. Você verá, conforme a Figura 3.6, que pode-se adicionar abas a aplicação,
e no neste caso criamos três abas: Home, Config, Favorites.

Figura 3.6 - Criando uma aplicação Tabbed


Clique no botão Finish e poderemos perceber uma estrutura diferente do nosso primeiro
projeto, o HelloWorld. No arquivo HelloWorld2.mxml, temos agora a utilização do
componente TabbedViewNavigatorApplication, e temos também a criação de
três ViewNavigators distintos, representando as abas (tabs) que criamos no assistente.
Para cada aba, temos uma view diferente, na qual poderemos adicionar mais views.

Através das tabs, temos a seguinte situação:

HelloWorld2.mxml

View 1.1

View 3.2

View 1.1 View 3.1

View 1 View 2 View 3

Tab1 Tab2 Tab3


Home Config Favorites

Quando alteramos entre as seções (tabs), o framework Flex preserva o estado na seção
anterior e carrega a view que da aba selecionada. Ou seja, a alteração entre uma aba e
outra ocorre de forma independente.

Qualquer view pode ser adicionada a qualquer seção, sem restrições. E claro, em tempo de
execução, somente uma view de é carregada por vez.
3.11 Configurando a disposição do dispositivo mobile (Retrato
ou paisagem)
Os dispositivos mobile possuem duas orientações que são chamadas de portrait e
landscape. O framework Flex também possui uma forma de poder gerenciar a disposição,
baseada no conceito de “states”, que é o mesmo conceito do desenvolvimento
web/desktop. Para que você possa utilizar este recurso, basta criar os states com estes
nomes e definir como será o layout da aplicação.

Isso será feito no exemplo HelloWorld3, conforme o código a seguir:


<?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="HomeView">

<s:states>
<s:State name="landscape"/>
<s:State name="portrait"/>
</s:states>

<s:layout>
<s:BasicLayout/>
</s:layout>
<s:Button label="Button"
x.landscape="10" y.landscape="10"
x.portrait="15" y.portrait="11"/>
<s:Button label="Button"
x.landscape="10" y.landscape="83"
x.portrait="363" y.portrait="11"/>
<s:Button label="Button"
x.landscape="10" y.landscape="156"
x.portrait="247" y.portrait="11"/>
<s:Button label="Button"
x.landscape="10" y.landscape="229"
x.portrait="131" y.portrait="11"/>
<s:Image width="402" height="284" source="android.gif"
x.landscape="126" y.landscape="10"
x.portrait="39" y.portrait="94"/>

</s:View>
Que resulta na seguinte disposição:

3.12 Persistência de dados na View


Toda aplicação, seja ela web/desktop ou mobile, trabalha necessariamente com dados. O
Framework Flex mobile possui diversos recursos para ajudar o desenvolvedor a manipular
estes dados. Inicialmente, temos no componente View, uma propriedade chamada data,
que é um objeto que armazena informações sobre o que está sendo exibida naquela View.

Você deve usar a propriedade data em todas as suas views, pois o framework cuida da
persistência desta propriedade automaticamente para você. Porquê? Por que uma
aplicação mobile tem constantes interrupções, tais como uma chamada do telefone (o que
interrompe a execução da aplicação), a um evento do calendário ou simplesmente a saída
do usuário para acessar outra aplicação. Quando isso acontece, o framework cuida para
manter essa persistência de dados na variável data, sem a necessidade de programação
extra.
O framework Flex possui duas formas de persistência de dados. A primeira delas é chamada
de “in memory” e limita-se a guardar a propriedade data de uma view enquanto a
aplicação estiver funcionando, e o usuário estiver navegando entre views.

A segunda forma de persistência é chamada de “in session”, e destina-se a armazenar


diversos estados da aplicação, como, por exemplo, a view aberta, juntamente com a
propriedade data, além da aba carregada em uma aplicação Tabbed. Para habilitar este
recurso, deve-se habilitar a propriedade persistNavigatorState de uma
TabbedViewNavigatorApplication e/ou ViewNavigatorApplication.

Se a propriedade persistNavigatorState estiver false,nenhuma persistência será


realizada, e você poderá utilizar o meio tradicional para isso, que é utilizando a classe
PersistenceManager, ou então usar o banco de dados SQLite.

No capítulo 3.3, vemos que um dos parâmetros do método pushView é justamente o


data, que será inserido na propriedade data da próxima view a ser carregada. Esta é a
melhor forma de se repassar um objeto para outra view.
4 Componentes do Flex Mobile Framework
A seguir veremos uma lista de todos os componentes que podem ser utilizados no
desenvolvimento Mobile. Veja que todos os componentes MX não são recomendados para
o uso em dispositivos mobile, com exceção dos charts (gráficos).

4.1 ActionBar
spark.components.ActionBar

O ActionBar é um componente composto de três áreas distintas: botões de navegação, uma


barra de títulos e botões de ação. Este componente é inserido automaticamente em uma
view, e você pode adicionar itens a ele através das propriedades navigationContent e
actionContent. O título pode ser alterado através da propriedade title.

4.2 BusyIndicator
spark.components.BusyIndicator

Este componente é usado para indicar alguma operação mais demorada no dispositivo
mobile. Ele substitui o “relógio” do ponteiro do mouse para as aplicações web/desktop,
mas deve ser implementado manualmente. O componente está sempre em “movimento”,
e para exibi-lo na tela, você deve usar a sua propriedade “visible”, conforme o exemplo a
seguir. Pode-se também utilizar a propriedade symbolColor para alterar a cor do
indicador e a propriedade rotationalInterval para alterar a velocidade do indicador.
<?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="HelloWorldBusyIndicator">

<s:layout>
<s:VerticalLayout
gap="10"
paddingLeft="10" paddingTop="10"
paddingRight="10" paddingBottom="10"
/>
</s:layout>

<s:actionContent>
<s:BusyIndicator id="bi" visible="false"
symbolColor="yellow"/>
</s:actionContent>

<s:Button label="Show Busy Indicator" width="100%">


<s:click>
<![CDATA[
this.bi.visible = true;
]]>
</s:click>
</s:Button>

<s:Button label="Hide Busy Indicator" width="100%">


<s:click>
<![CDATA[
this.bi.visible = false;
]]>
</s:click>
</s:Button>

</s:View>

4.3 TabbedViewNavigatorApplication
spark.components.TabbedViewNavigatorApplication

Quando escolhemos criar uma aplicação “Tabbed”, no assistente de criação do Flash Builder
4.6, a aplicação principal criada é justamente este componente. Um TabbedView cria uma
aplicação mobile dividida em seções, ou abas, que ficam localizadas na parte inferior do
dispositivo, conforme o exemplo a seguir:
<?xml version="1.0" encoding="utf-8"?>
<s:TabbedViewNavigatorApplication
xmlns:fx="http://ns.adobe.com/mxml/2009"

xmlns:s="library://ns.adobe.com/flex/spark"
>

<s:ViewNavigator label="Home" width="100%" height="100%"


firstView="views.HomeView"

icon="@Embed('icons/ic_menu_phone.png')"/>

<s:ViewNavigator label="Config" width="100%" height="100%"


firstView="views.ConfigView"

icon="@Embed('icons/ic_menu_wizard.png')"/>

<s:ViewNavigator label="Favorites" width="100%" height="100%"


firstView="views.FavoritesView"

icon="@Embed('icons/ic_menu_flash.png')"/>

</s:TabbedViewNavigatorApplication>

O resultado é semelhante a Figura 4.1.

Figura 4.1 - Tabbed Aplication


4.4 ViewNavigatorApplication
spark.components.ViewNavigatorApplication

O ViewNavigatorApplication também é usado para criar uma aplicação mobile, mas sem
seções (abas). Somente uma seção é criada, na qual podem ser adicionadas diversas views.

4.5 View
spark.components.view

O componente View é um dos principais componentes do framework mobile. Foi


amplamente discutido no capítulo 3. Resumindo, cada tela na aplicação que representa
uma informação é uma view.

4.6 ViewMenu
spark.components.ViewMenu

O ViewMenu é um componente “embutido” na view usado para criar um menu na


aplicação, que é chamado através do botão menu do dispositivo mobile. Mais informações
no capítulo 3.9.

4.7 Button
spark.components.Button

Representa um botão que pode ser clicado. Veja que tanto na web/desktop como no
mobile, o componente é o mesmo, mas a sua renderização é diferente. Devido ao conceito
de Skins, implementado a partir do Flex 4, o desenho do botão no Mobile é diferente do
web/desktop, devido ao tema mobile.swc.

Como propriedades principais, citamos o label, que determina o texto que aparecerá no
componente e também o evento click, disparado quando o usuário clica no botão.

Existem algumas formas de relacionar uma ação ao evento click, veja:

 <s:Button id="btn1" label="Button" click="{


navigator.pushView(views.HelloWorldAgain)}"/>

OU
<fx:Script>
<![CDATA[
import mx.controls.Alert;
protected function OnButtonClick (event:MouseEvent):void
{
navigator.pushView(views.HelloWorldAgain);
}

]]>
</fx:Script>

<s:Button id="btn2" label="Button" click="OnButtonClick (event)"/>

Ou

<s:Button id="btn3" label="Button">


<s:click>
<![CDATA[
navigator.pushView(views.HelloWorldAgain)
]]>
</s:click>
</s:Button>

Em , temos a forma mais simples e é usada para pequenas operações, como chamar um
outro método ou então chamar uma outra view. Veja que usamos a propriedade click=””
seguida do uso de chaves ( { ... } ), para delimitar um código ActionScript. Sempre que
quisermos chamar algum código, executar algo ou referenciar alguma variável dentro de
uma propriedade, devemos usar as chaves para delimitar o código MXML do código
ActionScript.

A segunda forma () referencia diretamente o evento click a um método, nesta caso
chamado de OnButtonClick. O método () deve ser definido entre a tag fx:Script, e
geralmente possui parâmetros relacionados ao evento. Esta segunda forma é muito
empregada quando estamos trabalhando em um projeto maior, no qual separamos
totalmente o código ActionScript do código mxml.

Em  temos outra forma de executar código ActionScript, mas este código é definido no
interior da tag s:Button. Desta forma, podemos escrever várias linhas de código (o que é
impossível em ) sem ter que criar um método separado como foi feito em .

Uma novidade na versão 4.6 é a adição da propriedade icon, que adiciona um ícone ao
botão, conforme o exemplo a seguir:
<s:Button id="button" label="myButton" icon="@Embed('about.png')"/>

4.8 CheckBox
spark.components.checkBox

O Checkbox é um componente usado para definir algum valor lógico, verdadeiro ou falso.
Consiste de uma caixa seguida de um Label que pode estar marcada ou não. A sua
propriedade principal é selected, estando true se estiver marcada ou false se não
estiver marcada.

4.9 Group
spark.components.group

O Group é um componente usado para agrupar componentes visuais. O Group pode ser
configurado para organizar os seus componentes em quatro disposições: vertical,
horizontal, livre ou lado a lado. Esta configuração é realizada através do parâmetro s:layout,
onde podemos fornecer os seguintes valores:

 BasicLayout: Semelhante ao Canvas no Flex 3


 HorizontalLayout: Semelhante ao HBox no Flex 3
 VerticalLayout: Semelhante ao VBox no Flex 3
 TileLayout: Semelhante ao Tile no Flex 3

Além do Group, temos também o HGroup e o VGroup. A diferença entre eles é que se
usarmos o Group, pode-se alterar a disposição (de vertical para horizontal, por exemplo)
em tempo de execução, enquanto que se usarmos o componente HGroup não poderemos
fazer isso. Isso não significa que um é melhor que o outro, apenas que podem ser usados
dependo da sua necessidade.

O componente Group foi criado para substituir os componentes VBox, HBox, Canvas e Tile
do Flex 3. Ele possui mais performance e obedece às regras dos componentes Spark, como
por exemplo a separação entre lógica e layout. Relembrando, mesmo o componente Group
sendo Spark, pode-se adicionar componente mx nele. Vamos a um simples exemplo:
<s:Group>
<s:layout>
<s:VerticalLayout paddingTop="10"/>
</s:layout>

<s:Button label="Hello"/>
<s:Button label="World"/>
<mx:ProgressBar/>

</s:Group>

4.10 Image
spark.components.image

Usado para carregar imagens na sua aplicação, que podem ser JPEG, PNG, GIF e até SWF. A
principal propriedade deste componente é source, que indica o caminho completo da
imagem a ser carregada. As imagens podem ser carregadas de duas formas distintas:

 Elas podem ser incorporadas à aplicação, carregando automaticamente, mas


aumentando o tamanho do arquivo SWF da aplicação (Ou o tamanho final do seu
aplicativo). Use este método para imagens pequenas do sistema, como ícones e
bordas. Lembre-se que quanto mais imagens adicionar, maior sua aplicação final
ficará, comprometendo o seu carregamento inicial. Para que uma imagem seja
incorporada à aplicação, use @Embed(source=’nome do arquivo’) na propriedade
source.

 Elas podem ser carregadas em runtime, ou seja, assim que são requisitadas. Por
exemplo, existe um Panel que tem um foto. Este Panel é aberto na aplicação
somente se clicar em um botão. Até o momento a imagem não está carregada.
Assim que o botão for clicado, o Panel é carregado e o componente s:image é
construído. Automaticamente, o componente Image faz uma requisição (via http)
da imagem, exibindo-a assim que o download da imagem for completado. Todo
este processo é automático, e pode demorar um pouco dependendo da velocidade
de conexão e do tamanho da imagem, o que pode não ser agradável para o
usuário, até porque o dispositivo mobile precisará de uma conexão com a internet.

É preciso compreender que a escolha de uma destas duas formas de carregamento pode
afetar o sistema, então é preciso escolher com cuidado qual caminho tomar. Uma dica é
deixar imagens pequenas incorporadas ( lembre-se, source=”@Embed(‘icone.png’)”), além
da imagem de fundo (somente uma, com no máximo 50K). Outras imagens, como fotos,
devem ser carregadas somente quando requisitadas.

Uma novidade da versão 4.6 é que o Spark Image contém agora uma barra de progressos
para mostrar o carregamento da imagem e também uma imagem indicando se o link está
quebrado.

4.11 Label
spark.components.label

O label é o componente usado para exibir texto na tela. A propriedade text é usada para
definir qual texto será exibido. O texto não pode conter caracteres HTML, e para que possa
ser formatado você pode usar propriedades como fontFamily e fontSize, entre outros.

O componente Label spark usa FTE – Flash Text Engine, o que não acontecia no
componente Label do Flex 3 (mx), que usava a classe TextField. Isso garante um melhor
suporte a idiomas, além de possibilitar que o label possa ter múltiplas linhas. O Label spark
não pode ser selecionado e não possui formatação (como o uso de <b> para negrito, por
exemplo).

Exemplo:
<s:Label id=”myLabel” text=”Hello World”/>

4.12 List
spark.components.list

O componente List exibe uma lista de itens, que podem ser selecionados. É semelhante ao
controle Select do HTML. Dentre suas principais propriedades, temos o dataProvider,
labelField, allowMultipleSelection que permite que mais de um item seja selecionado e
selectedItens que retorna um vetor de objetos selecionados.

O list é um componente importante no mobile, sendo utilizado em quase todas as views


para exibir informações, e será visto com mais detalhes no capítulo 5.
4.13 RadioButton
spark.components.RadioButton

O componente RadioButton é usado para que possamos escolher uma opção entre várias. É
o mesmo comportamento do controle Radio do HTML. As duas principais propriedades
deste componente são label, que exibe o texto do RadioButton, e groupName, que
identifica o grupo onde o RadioButton está inserido. Esta propriedade é importante porque
somente uma opção entre os RadioButtons deve ser escolhida.

Outras propriedades do RadioButton são: selected, que indica se o Radio está selecionado e
value, que indica um valor que será exibido através do componente RadioButtonGroup,
visto na próxima seção.

4.14 RadioButtonGroup
spark.components.RadioButtonGroup

O RadioButtonGroup não é um componente visual, e foi criado especialmente para


trabalhar em conjunto com o RadioButton. A sua finalidade básica é descobrir quais dos
RadioButtons está selecionado. Como não é um componente visual, este componente deve
ser inserido na tag fx:Declarations. Vamos a um exemplo:
<fx:Declarations>
<s:RadioButtonGroup id="formaPagamento" />
</fx:Declarations>

<s:RadioButton id="boleto" label="Boleto" groupName="formaPagamento"


selected="true"/>
<s:RadioButton id="cartao" label="Cartão de Crédito"
groupName="formaPagamento"/>

<s:RadioButton id="deposito" label="Depósito"


groupName="formaPagamento"/>

<s:Button label="Descobrir opção escolhida">


<s:click>
<![CDATA[

mx.controls.Alert.show(formaPagamento.selectedValue.toString()
);
]]>
</s:click>
</s:Button>
Neste exemplo, criamos três RadioButtons, e a propriedade groupName destes
componentes apontam para outro componente, o RadioButtonGroup, cujo id é
formaPagamento.

Depois de criar estes quatro componentes (3 RadioButtons + 1 RadioButtonGroup), basta


utilizar a propriedade selectedValue do componente RadioButtonGroup para descobrir
quais dos RadioButtons está selecionado.

4.15 TextInput
spark.components.TextInput

O componente TextInput é um dos mais usados para entrada de dados. Ele representa uma
caixa onde o usuário pode inserir texto. A propriedade mais importante dele é o text, que
representa o texto que está escrito na caixa de texto. Outras propriedades importantes são
maxChars, que indica a quantidade máxima de caracteres, displayAsPassword, que indica
se a caixa de texto deve omitir o que está sendo digitado e prompt, que exibe uma
mensagem dentro da caixa de texto até que o usuário selecione o componente.

4.16 SplitViewNavigator
spark.components.SplitViewNavigator

É um novo componente da versão 4.6, criada especialmente para tablets e para que
possamos criar aplicações semelhantes entre um celular e um tablet. Este componente
divide-se em dois layouts, ou duas views. A disposição das views depende da orientação do
dispositivo (landscape ou portait). A idéia básica é que, quando o dispositivo estiver “em
pé”, a primeira view possa ser ocultada, possibilitando uma melhor visualização dos dados.
Neste modo, a primeira view pode surgir em um popup, conforme a Figura 4.2.
Figura 4.2 - SplitView em ação

4.17 CallOutButton
spark.components.CalloutButton

Exibe um popup em formato de “balão”, para que possamos adicionar conteúdo nele. As
possibilidades de Design são infinitas e este componente, se bem usado, melhora o design
da interface do dispositivo e da experiência do usuário (Figura 4.3).
Figura 4.3 - Exemplo de CalloutButton

4.18 SpinnerList e DateSpinner


spark.components.SpinnerList

Outro novo componente da versão 4.6, é usado como um combobox para que seja
selecionado um item em diversos (Figura 4.4).

Figura 4.4 – DateSpinner


4.19 ToogleSwitch
spark.components.ToogleSwitch

Outro componente muito comum em dispositivos mobile, utilizado para selecionar dois
valores, geralmente verdadeiro ou falso.

4.20 Alert
O Alert (mx.controls.alert) não está disponível para os dispositivos mobile, então
precisamos de alguma forma criar um. Para fazer isso podemos criar um componente
personalidado, conforme o código a seguir:
<?xml version="1.0" encoding="utf-8"?>
<s:SkinnablePopUpContainer xmlns:fx="http://ns.adobe.com/mxml/2009"

xmlns:s="library://ns.adobe.com/flex/spark"
width="100" height="50">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
import flash.display.DisplayObjectContainer;
[Bindable]
public var title:String;

[Bindable]
public var message:String;

public function
show(message:String,title:String,owner:DisplayObjectContainer,
modal:Boolean=false):void
{
this.message = message;
this.title = title;
this.open(owner, modal);
}
]]>
</fx:Script>
<s:TitleWindow title="{title}" close="close()">
<s:VGroup horizontalAlign="center" paddingTop="8"
paddingBottom="8" paddingLeft="8" paddingRight="8" gap="5"
width="100%">
<s:Label text="{message}"/>
<s:Button label="OK" click="close()"/>
</s:VGroup>
</s:TitleWindow>
</s:SkinnablePopUpContainer>

Após criar o componente, você pode chamá-lo da seguinte forma:


<?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"
applicationDPI="160">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value
objects) here -->
</fx:Declarations>

<s:Button label="open alert">


<s:click>
<![CDATA[
var aviso:MyAlert = new MyAlert();
aviso.show("Esta é uma
mensagem","Teste",this,true);
]]>
</s:click>
</s:Button>

</s:Application>
5 Trabalhando com listas
Exibir listas no framework mobile será uma das tarefas mais rotineiras do seu
desenvolvimento. É importante comentar novamente que você não deve usar o
componente DataGrid para exibir dados na tela, mas sim o componente List.

A forma mais simples de exibir uma lista de itens no framework mobile é através do
exemplo a seguir:
<s:List id="list" width="100%" labelField="firstName">
<s:dataProvider>
<s:ArrayList>
<fx:Object firstName="Daniel" />
<fx:Object firstName="Fulano" />
<fx:Object firstName="Beltrano" />
</s:ArrayList>
</s:dataProvider>
</s:List>

Por mais simples que este exemplo possa parecer, ele explica duas propriedades
importantes do List. A primeira delas é a propriedade dataProvider, que indica a fonte
de dados da lista. Geralmente esta fonte é um ArrayList de objetos. Outra propriedade
importante é labelField, que indica qual propriedade do objeto que será exibido na
lista.

5.1 O evento change


Quando o usuário seleciona um item da lista, o evento change é disparado. Podemos
capturá-lo de acordo com o exemplo a seguir:
<s:List id="list" width="100%" labelField="firstName">
<s:dataProvider>
<s:ArrayList>
<fx:Object firstName="Daniel" />
<fx:Object firstName="Fulano" />
<fx:Object firstName="Beltrano" />
</s:ArrayList>
</s:dataProvider>

<s:change>
<![CDATA[
this.title = list.selectedItem.firstName;
]]>
</s:change>

</s:List>

Neste exemplo, usamos o evento change para capturar o momento em que o usuário
selecionou um item da lista. Quando isso acontece, instantaneamente a propriedade
selectedItem é preenchida com o objeto que foi selecionado, e podemos usá-lo para
realizar algum tipo de processamento. Neste caso, apenas mudamos o título da view.

Caso a propriedade allowMultipleSelection esteja com o valor true (o padrão é


false), você deve usar a propriedade selectedItems, que é uma lista dos objetos
selecionados. O exemplo a seguir ilustra esta característica:
<s:List id="list" width="100%" labelField="firstName"
allowMultipleSelection="true"
>
<s:dataProvider>
<s:ArrayList>
<fx:Object firstName="Daniel" />
<fx:Object firstName="Fulano" />
<fx:Object firstName="Beltrano" />
</s:ArrayList>
</s:dataProvider>

<s:change>
<![CDATA[
var names:String = "";
var poeVirgula:Boolean = false;

for each (var item:Object in list.selectedItems)


{
if (poeVirgula) { names += ", " }

names += item.firstName;

poeVirgula = true;

}
this.title = names;

]]>
</s:change>

</s:List>

Neste exemplo criamos um laço para exibir a lista de nomes selecionados, através da
propriedade selectedItems.
5.2 Item Renderers no List
Um Item Renderer é uma forma de “desenhar” cada linha da lista. No exemplo anterior,
cada linha era representada por um label simples, mas podemos alterar este
comportamento com item renderers, podendo, por exemplo, incluir uma foto ou então
mais texto além do normal.

Na Figura 5.1, podemos ver o componente List com a sua renderização normal, um label. Já
na Figura 5.2, temos um item renderer customizado, incluindo um ícone e um label. Existem
centenas de possibilidades para que você possa criar suas listas personalizadas, mas por
uma questão de performance, é bom compreender as regras citadas a seguir:

 Escreva item renderers em Action Script, sempre que possível. Como você deve
saber, todo componente MXML é “traduzido” para o Action Script em tempo de
execução, e isso possui um custo alto para dispositivos móveis.
 Não reaproveite os item renderers que você criou no Flex web/desktop.
 Item Renderers para mobile devem herdar de de LabelItemRenderer
 Tente usar somente LabelItemRenderer e IconItemRenderer, na maioria dos casos
eles resolvem todos os tipos de visualização. Estes podem ser em MXML.
 Não crie listas com mais de 50 itens. Se isso acontecer, o seu dispositivo mobile
pode ficar lento. Se você precisar criar listas grandes, use paginação diferenciada
(através de um botão “mais”).

Figura 5.1 - Componente List com renderização padrão, via componente Label
Figura 5.2 - Componente List com renderização diferenciada

5.3 Conhecendo o IconItemRenderer


No exemplo a seguir iremos utilizar o componente IconItemRenderer, repassando somente
as propriedades necessárias para criar uma lista com imagens. Vejas que em nenhum
momento fazemos referência ao componente image ou ao componente bitmapImage,
deixando o framework Flex com esta responsabilidade:
<s:List width="100%" height="100%">
<s:dataProvider>
<s:ArrayList>
<fx:Object name="Edit" icon="icons/edit.png"/>
<fx:Object name="error" icon="icons/error.png"/>
<fx:Object name="exchange"
icon="icons/exchange.png"/>
<fx:Object name="export1"
icon="icons/export1.png"/>
<fx:Object name="export2"
icon="icons/export2.png"/>
<fx:Object name="find" icon="icons/find.png"/>
</s:ArrayList>
</s:dataProvider>
<s:itemRenderer>
<fx:Component>
<s:IconItemRenderer
iconField="icon"
labelField="name">
</s:IconItemRenderer>
</fx:Component>
</s:itemRenderer>
</s:List>

Se os ícones estiverem no lugar certo, o resultado deste código é visto na Figura 5.3.
Figura 5.3 - Renderização de um IconItemRenderer

O componente IconItemRenderer não trabalha apenas com as duas propriedades


iconField e labelField. Além dela, também temos a propriedade messageField,
que é uma mensagem que ficará abaixo do label, sem falar que temos iconFunction,
labelFunction e messageFunction, que são funções chamadas a cada interação
dos itens do List que retornam uma String contendo o texto que será exibido no item.

Como temos que pensar sempre em listas rápidas, sem eventuais “firulas”, recomenda-se
que utilize o IconItemRenderer em 99% das listas da sua aplicação mobile. No próximo
exemplo, exibimos como criar uma lista mais elaborada, envolvendo diversos conceitos do
IconItemRenderer, que resulta em uma lista conforme a Figura 5.4.
<?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="Adobe Suported Devices">

<fx:Style>
.messageStyle {
fontSize: 15;
color: #aaaa00;
}
</fx:Style>

<s:List width="100%" height="100%">


<s:dataProvider>
<s:ArrayList>
<fx:Object name="Acer Liquid"
image="device/acer_liquid.png" info="Include with Android 2.2 update"
/>
<fx:Object name="Acer Liquid Ferrari"
image="device/acer_ferrari.png" info="Include with Android 2.2
update" />
<fx:Object name="Acer Stream"
image="device/acer_android.png" info="Include with Android 2.2
update"/>
</s:ArrayList>
</s:dataProvider>
<s:itemRenderer>
<fx:Component>
<s:IconItemRenderer
iconField="image"
iconWidth="160"
iconHeight="114"
labelField="name"
messageField="info"
messageStyleName="messageStyle"
fontStyle="italic"
>
</s:IconItemRenderer>
</fx:Component>
</s:itemRenderer>
</s:List>

</s:View>
Figura 5.4 - Uma lista de itens mais elaborada
6 Criando a aplicação FlexTasks
Somente com o conteúdo aprendido até agora já é possível criar aplicações simples, que
exigem pouco processamento e memória do dispositivo. A idéia inicial desta aplicação é
criar um gerenciador de tarefas, capaz de controlar nossas pequenas tarefas do dia a dia.

Uma aplicação para gerenciar tarefas é formada pelas tarefas que ainda não foram
concluídas, e pelas tarefas já concluídas. Com isso podemos criar duas listas, de forma a
carregar inicialmente somente a lista de tarefas não concluídas. Veja que estamos, a todo
momento, pensando em performance, e precisamos focar o desenvolvimento da aplicação
neste quesito. É de imaginar que o usuário não deseja ver, inicialmente, a lista de tarefas
concluídas, então não há motivos para carregá-la na memória do celular, ainda mais que,
com o passar do tempo, esta lista tende a crescer muito.

Isto significa que a lista de tarefas concluídas não será vista na tela inicial da aplicação,
mas estará carregada em uma variável na memória. Este conceito pode ser melhorado caso
você deseje otimizar ainda mais a performance do dispositivo.

Além destas duas listas, também temos a tela de criação/edição de tarefas, com os
seguintes campos:

 Nome da tarefa
 Descrição da tarefa
 Prioridade (0,1,2)
 Concluída (Sim, Não)

6.1 Criando o projeto


Cmo o Flash Builder 4.6 aberto, acione o menu File > New > Flex Mobile Project. Em
Project Name, coloque “FlexTasks”. Clique no botão Next. Em Target plataforms,
escolha a versão que será compilada o projeto, caso deseje algo específico.

Em Application Tamplate, selecione “Tabbed Application”, e adicione três tabs: “Tarefas”,


“Concluídas”, “Opções”, conforme a Figura 6.1. Clique em Finish.
Figura 6.1 – Criando as abas da aplicação FlexTasks

Após criar a aplicação, execute-a clicando no botão Run. Surge a tela para configurarmos o
dispositivo padrão, que neste caso será um Google Nexus One. Selecione-o, clique em
Apply e depois em Run. Você verá a aplicação de acordo com a Figura 6.2.
Figura 6.2 Tela inicial da aplicação

O código gerado é composto por quatro arquivos MXML, veja:

 /FlexTasks/src/FlexTasks.mxml

É a aplicação principal, e possui a chamada para três abas. Veja que, se você deseja
adicionar mais abas ou retirá-las, deverá editar os componentes ViewNavigator, tanto no
modo source quanto no modo design.
<?xml version="1.0" encoding="utf-8"?>
<s:TabbedViewNavigatorApplication
xmlns:fx="http://ns.adobe.com/mxml/2009"

xmlns:s="library://ns.adobe.com/flex/spark">

<s:ViewNavigator label="Tarefas" width="100%" height="100%"


firstView="views.TarefasView"/>
<s:ViewNavigator label="Concluídas" width="100%" height="100%"
firstView="views.ConcluidasView"/>
<s:ViewNavigator label="Opções" width="100%" height="100%"
firstView="views.OpesView"/>

</s:TabbedViewNavigatorApplication>

Já no package “views”, temos três arquivos mxml que são as views de cada aba criada:
ConcluidasView.mxml, OpcoesView.mxml e TarefasView.mxml.

No assistente de criação do projeto, caso tenha usado acentuação no nome das abas, o
nome dos arquivos será comprometido. Por exemplo, Opções será OpesView.mxml. Neste
caso, faça o rename do arquivo (Selecione o arquivo e aperte F2).

Não é necessário a palavra View no nome do Arquivo, porque todas são views, não existe
distinção. Então iremos renomeá-las para “Concluidas.mxml”, “Opcoes.mxml” e
“Tarefas.mxml”. Use o F2 dentro do Flex, não faça o rename no sistema de arquivos, pois o
Flex precisa atualizar as referências em toda a aplicação.

6.2 Incluindo ícones


4
Vamos adicionar alguns ícones nas abas, e para isso podemos acessar este site e baixar o
kit de ícones gratuitos. Existe uma versão paga com mais de 140 ícones, caso deseje
comprar.

Após realizar o download, copie os ícones que deseja usar para a pasta “src/assets/icons”
da aplicação. Crie estas pastas se necessário.

 A pasta “assets” é um padrão informal da Adobe, que significa “recursos”. Lá inserimos


todas as images, ícones, estilos e outros recursos da aplicação.

Para inserir os ícones, use a propriedade icon do ViewNavigator, veja:

// ...

<s:ViewNavigator label="Tarefas"
width="100%"

4
http://www.androidicons.com/freebies.php
height="100%"
firstView="views.TarefasView"
icon="@Embed(source='assets/icons/ic_menu_database.png')"
/>

<s:ViewNavigator label="Concluídas"
width="100%"
height="100%"
firstView="views.Concluidas"
icon="@Embed(source='assets/icons/ic_menu_tick.png')"
/>

<s:ViewNavigator label="Opções"
width="100%"
height="100%"
firstView="views.Opcoes"
icon="@Embed(source='assets/icons/ic_menu_equalizer.png')"
/>

// ...

6.3 Persistência de dados


Antes de criarmos qualquer tela (view), temos que pensar em como será a persistência de
dados da aplicação. Existem duas formas básicas de persistir dados em uma aplicação
mobile. A primeira delas é usar um servidor (PHP, Java, etc) e persistir os dados no próprio
servidor. Na segunda forma, os dados são armazenados no próprio dispositivo, e isso é
realizado através do próprio framework mobile.

Como foi visto no capítulo 3.12, para ativar a persistência de dados, temos que ativar a
propriedade persistNavigatorState, da seguinte forma:

 /FlexTasks/src/FlexTasks.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:TabbedViewNavigatorApplication
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
persistNavigatorState="true"
>

// ...
Somente com o persistNavigatorState é possível guardar diversas informações
sobre o estado das telas, mas é preciso também guardar a lista de tarefas realizadas e a lista
de tarefas a realizar, e fazemos isso através de dois métodos da aplicação, que são:

 setProperty(chave, valor)
 getProperty(chave)
Para usar estes métodos, precisamos instanciar a classe PersistenceManager, que é uma
nativa do Flex 4.6, que possui a implementação do recurso de SharedObject, que já deve ser
conhecido pelos desenvolvedores Flex.

Apesar da aplicação ser de pequeno porte, iremos usar uma estrutura formada por
camadas, onde a camada de negócios é separada da camada de visualização, tentando
imitar sempre o padrão MVC. Como Model, temos o arquivo “Task.as”, que contém as
propriedades da tarefa. Como no futuro chamaremos este tipo de classe como “Value
Objetcs”, criaremos o package “vos” e adicionaremos a classe neste package. Navegue até
File, New, Action Script Class e crie a classe conforme a Figura 6.3.
Figura 6.3 - Criando a classe Task.as

 /FlexTasks/src/vos/Task.as
package vos
{
[Bindable]
public class Task
{
public var name:String;
public var description:String;
public var priority:uint=1;
public var complete:Boolean;

public function get icon():String


{
if (this.complete)
return "assets/icons/checks.png";

switch(priority)
{
case 1:
{
return "assets/icons/alta.png";
break;
}

case 2:
{
return "assets/icons/normal.png";
break;
}

case 3:
{
return "assets/icons/baixa.png";
break;
}

return "assets/icons/normal.png";
}
}
}

A classe Task.as representa uma tarefa única. Ela é [Bindable] porque iremos editar as
propriedades da tarefa em formulários, realizando o link de dados do formulário ao objeto.
A propriedade icon é uma forma de retornar o ícone da tarefa, de acordo com algumas
propriedades. Por exemplo, se a tarefa estiver concluída, retornaremos o ícone “checks”.

Agora que criamos a classe vo que representa as tarefas, vamos criar a classe que gerencia
as tarefas. Veja que ainda não estamos nos preocupando com as telas em si, somente com
a implementação. Fazemos isso para separar cada parte da aplicação em uma camada.
Vamos criar a classe TaskController no package classes, com o seguinte código:

 /src/classes/TaskController.as
package classes
{
import flash.events.Event;
import flash.utils.flash_proxy;
import mx.collections.ArrayList;

import spark.managers.PersistenceManager;

import vos.Task;

public class TaskController


{
private const TASKS_COMPLETAS:String =
"TASKS_COMPLETAS";
private const TASKS_INCOMPLETAS:String =
"TASKS_IMCOMPLETAS";

//Armazena as tarefas que estão completas


private var _completas:ArrayList;

//Armazena as tarefas que estão incompletas


private var _incompletas:ArrayList;

//Variável para "segurar" o persistence manager


private var pM:PersistenceManager;

public function TaskController()


{
/* Ativa o PersistentManager */
pM = new PersistenceManager();
pM.load();

initTaks();

private function initTaks():void


{

_completas = pM.getProperty(this.TASKS_COMPLETAS)
as ArrayList;

if (_completas==null)
_completas = new ArrayList();

_incompletas =
pM.getProperty(this.TASKS_INCOMPLETAS) as ArrayList;

if (_incompletas==null)
_incompletas = new ArrayList();
}

public function save():void


{
pM.setProperty(this.TASKS_COMPLETAS,completas);

pM.setProperty(this.TASKS_INCOMPLETAS,incompletas);
pM.save();
}

public function deleteAll():void


{
pM.clear();
initTaks();
}

public function removeIncompleta(task:Task):void


{
this.incompletas.removeItem(task);
this.save();
}

public function removeCompleta(task:Task):void


{
this.completas.removeItem(task);
this.save();
}

public function get incompletas():ArrayList


{
return _incompletas;
}

public function set incompletas(value:ArrayList):void


{
_incompletas = value;
}

public function get completas():ArrayList


{
return _completas;
}

public function set completas(value:ArrayList):void


{
_completas = value;
}

}
}
Como a classe TaskController é responsável em gerenciar os dados das tarefas, tudo relativo
a este gerenciamento está nela. Veja que criamos inicialmente dois arrays, que vão
representar as tarefas incompletas e as tarefas completas.

 Pessoal, me perdoem por misturar palavras em inglês/português no mesmo


sistema. O correto seria utilizar tudo em inglês...

Também criamos a variável pM, que apresenta a classe PersistenceManager e provê a


persistência de dados da aplicação. No método construtor, instanciamos o pM e chamamos
o método initTasks, que irá iniciar os arrays das tarefas.

No método initTasks, instanciamos os arrays de tarefas utilizando o método


getProperty do PersistenceManager. Depois temos o método Save, que usa o método
setProperty do PersistenceManager para poder salvar os arrays na memória do
dispositivo. Os outros métodos são relacionados a remover todos os itens ou então
remover itens de cada tipo de tarefa.

Agora que criamos o TaskController, podemos adicioná-lo na aplicação, e isso é feito no


mxml principal da app, veja:

/FlexTasks1/src/FlexTasks.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:TabbedViewNavigatorApplication
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
persistNavigatorState="true"
initialize="OnInit(event)"
>

<fx:Style source="assets/styles/style.css"/>

<fx:Script>
<![CDATA[
import classes.TaskController;

import flash.net.registerClassAlias;

import mx.events.FlexEvent;

import vos.Task;

//Variável que controla as tarefas


public var taskController:TaskController;
//É sempre bom registrar as classes Vo
registerClassAlias("Task",Task);

//Executado quando a aplicação estiver pronta


protected function OnInit(event:FlexEvent):void
{
taskController = new TaskController();
}

]]>
</fx:Script>

<s:ViewNavigator label="Tarefas"
width="100%"
height="100%"
firstView="views.Tarefas"

icon="@Embed(source='assets/icons/ic_menu_database.png')"
/>

<s:ViewNavigator label="Concluídas"
width="100%"
height="100%"
firstView="views.Concluidas"

icon="@Embed(source='assets/icons/ic_menu_tick.png')"
/>

<s:ViewNavigator label="Opções"
width="100%"
height="100%"
firstView="views.Opcoes"

icon="@Embed(source='assets/icons/ic_menu_equalizer.png')"
/>

</s:TabbedViewNavigatorApplication>

Na aplicação principal, no evento onInit, criamos a variável taskController que é


do tipo TaskController, e será acessada por toda a aplicação. Depois, para cada aba do
ViewNavigator, adicionamos um ícone através da propriedade icon. A primeira view
“Tarefas” apresenta as tarefas não concluídas, veja:
 /src/views/Tarefas.mxml
<?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="Tarefas">
<fx:Script>
<![CDATA[
import mx.core.FlexGlobals;

import vos.Task;
]]>
</fx:Script>

<s:actionContent>
<s:Button icon="@Embed('assets/icons/plus.png')">
<s:click>
<![CDATA[
this.navigator.pushView(InserirTarefa,new
Task());
]]>
</s:click>
</s:Button>
</s:actionContent>

<s:List id="listConcluidas"
width="100%" height="100%"

itemRenderer="itemRenderers.CompletasItemRenderer"
>
<s:creationComplete>
<![CDATA[
listConcluidas.dataProvider =
FlexGlobals.topLevelApplication.taskController.incompletas;
]]>
</s:creationComplete>
<s:change>
<![CDATA[
if (listConcluidas.selectedItem!=null)

navigator.pushView(views.VerTarefa,listConcluidas.selectedItem
);
]]>
</s:change>
</s:List>

</s:View>
A lista de tarefas não concluídas usa a variável taskController.incompletas como
dataProvider. Como você pode ver, usamos a variável FlexGlobals.topLevel
Application para referenciar a aplicação principal. Quando clica no botão para
adicionar uma nova tarefa, usamos o pushView para navegar até a view InserirTarefa,
repassando como parâmetro data uma nova tarefa (new Task()). Veja também que usamos
o itemRenderer TaskItemRenderers, exibido logo a seguir:

 /src/itemRenderers/TaskItemRenderer.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:IconItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"

xmlns:s="library://ns.adobe.com/flex/spark"
labelField="name"
messageField="description"
iconWidth="32"
iconHeight="32"
iconField="icon"
messageStyleName="messageStyle"
decorator="assets/icons/play.png"
>
</s:IconItemRenderer>

O item renderer usa as propriedades do IconItemRenderer para configurar uma lista de


itens como o título, descrição e ícone.

Quando o usuário seleciona o botão adicionar, abrimos a view InserirTarefa.mxml, veja:

src/views/InserirTarefa.mxml
<?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 Tarefa">

<s:layout>
<s:FormLayout paddingBottom="10" paddingLeft="10"
paddingRight="10" paddingTop="10"
gap="30"
/>
</s:layout>

<fx:Declarations>

<s:RadioButtonGroup id="prioridade"
selectedValue="@{data.priority}"/>
</fx:Declarations>

<fx:Script>
<![CDATA[
import mx.core.FlexGlobals;

import spark.transitions.FlipViewTransition;

import vos.Task;
]]>
</fx:Script>

<s:navigationContent>
<s:Button icon="@Embed('assets/icons/arrowleft.png')">
<s:click>
<![CDATA[
navigator.popView();
]]>
</s:click>
</s:Button>
</s:navigationContent>

<s:actionContent>
<s:Button icon="@Embed('assets/icons/plus.png')">
<s:click>
<![CDATA[

FlexGlobals.topLevelApplication.taskController.incompletas.add
Item(data);

FlexGlobals.topLevelApplication.taskController.save();
navigator.popView();
]]>
</s:click>
</s:Button>
</s:actionContent>

<s:TextInput width="100%" prompt="Nome da tarefa"


text="@{data.name}"/>

<s:VGroup>
<s:RadioButton group="{prioridade}" value="1"
label="Alta"/>
<s:RadioButton group="{prioridade}" value="2"
label="Normal"/>
<s:RadioButton group="{prioridade}" value="3"
label="Baixa"/>
</s:VGroup>
<s:TextArea width="100%" height="200" prompt="Descrição"
text="@{data.description}"/>

<s:Spacer height="30"/>
<s:HGroup width="100%">
</s:HGroup>

</s:View>

Veja que para inserir uma tarefa, usamos o arroba (@) para ligar cada valor de um campo a
propriedade da variável data. Quando o usuário confirma os dados, clicando no botão
“mais”, adicionamos a tarefa na lista de tarefas incompletas (usando novamente o
topLevelApplication). Após adicionar o item, fazemos o save() e depois usamos o
popView para voltar a view “Tarefas”.

Quando clicamos em uma tarefa, abrimos a view VerTarefa, com o seguinte código:

 /src/views/VerTarefa.mxml
<?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="Tarefa">
<fx:Script>
<![CDATA[
import classes.TaskController;

import itemRenderers.TaskItemRenderer;

import mx.core.FlexGlobals;

import vos.Task;
]]>
</fx:Script>

<s:navigationContent>
<s:Button icon="@Embed('assets/icons/arrowleft.png')">
<s:click>
<![CDATA[
navigator.popView();
]]>
</s:click>
</s:Button>
</s:navigationContent>

<s:actionContent>
<s:Image source="{data.icon}" width="32" height="32"/>
<s:Spacer width="10"/>
</s:actionContent>

<s:layout>
<s:VerticalLayout
paddingBottom="10"
paddingLeft="10"
paddingRight="10"
paddingTop="10"
/>
</s:layout>

<s:Label text="{data.name}" styleName="nomeTarefaLabel"/>


<s:TextArea text="{data.description}"
styleName="descricaoTarefaLabel" height="200"
editable="false"
/>

<s:Spacer height="50"/>
<s:VGroup width="100%"
horizontalAlign="center">

<s:Button label="Completar"
visible="{!data.complete}"
height="{!data.complete?100:0}" width="100%">
<s:click>
<![CDATA[
vgroupCompletar.visible = true;
vgroupCompletar.height=100;
]]>
</s:click>
</s:Button>

<s:HGroup id="vgroupCompletar" width="100%"


visible="false"
horizontalAlign="center" height="0">
<s:Button label="Sim" width="100">
<s:click>
<![CDATA[
(data as Task).complete = true;

(FlexGlobals.topLevelApplication.taskController as
TaskController).removeIncompleta(data as Task);
(FlexGlobals.topLevelApplication.taskController as
TaskController).completas.addItem(data);

(FlexGlobals.topLevelApplication.taskController as
TaskController).save();
vgroupCompletar.visible = false;
vgroupCompletar.height=0;
]]>
</s:click>
</s:Button>
<s:Button label="Não" width="100">
<s:click>
<![CDATA[
vgroupCompletar.visible=false;
vgroupCompletar.height=0;
]]>
</s:click>
</s:Button>
</s:HGroup>

<s:Button label="Editar" width="100%">


<s:click>
<![CDATA[

this.navigator.pushView(EditarTarefa,this.data);
]]>
</s:click>
</s:Button>

<s:Button label="Apagar" width="100%">


<s:click>
<![CDATA[
vgroupApagar.visible =
!vgroupApagar.visible;
]]>
</s:click>
</s:Button>

<s:HGroup id="vgroupApagar" width="100%" visible="false"


horizontalAlign="center">
<s:Button label="Sim" width="100">
<s:click>
<![CDATA[

if ((data as Task).complete)
(FlexGlobals.topLevelApplication.taskController as
TaskController).removeCompleta(data as Task);
else

(FlexGlobals.topLevelApplication.taskController as
TaskController).removeIncompleta(data as Task);

this.navigator.popView();
]]>
</s:click>
</s:Button>
<s:Button label="Não" width="100">
<s:click>
<![CDATA[
vgroupApagar.visible=false;
]]>
</s:click>
</s:Button>
</s:HGroup>

</s:VGroup>

</s:View>

Quando visualizamos uma tarefa, podemos realizar algumas ações com ela. A primeira
delas é concluir uma tarefa, que irá retirar a tarefa do array de incompletas e adicionar no
array de completas. Depois temos a ação de editar a tarefa, que irá chamar uma nova View
e a ação de apagar a tarefa. A view editar é exibida logo a seguir:

 src/views/EditarTarefa.mxml
<?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 Tarefa">

<s:layout>
<s:FormLayout paddingBottom="10" paddingLeft="10"
paddingRight="10" paddingTop="10"
gap="30"
/>
</s:layout>

<fx:Declarations>
<s:RadioButtonGroup id="prioridade"
selectedValue="@{data.priority}"/>

</fx:Declarations>

<fx:Script>
<![CDATA[
import mx.core.FlexGlobals;

import spark.transitions.FlipViewTransition;

import vos.Task;
]]>
</fx:Script>

<s:navigationContent>
<s:Button icon="@Embed('assets/icons/arrowleft.png')">
<s:click>
<![CDATA[
navigator.popView();
]]>
</s:click>
</s:Button>
</s:navigationContent>

<s:TextInput width="100%" prompt="Nome da tarefa"


text="@{data.name}"/>

<s:VGroup>
<s:RadioButton group="{prioridade}" value="1"
label="Alta"/>
<s:RadioButton group="{prioridade}" value="2"
label="Normal"/>
<s:RadioButton group="{prioridade}" value="3"
label="Baixa"/>
</s:VGroup>

<s:TextArea width="100%" height="200" prompt="Descrição"


text="@{data.description}"/>

<s:Spacer height="30"/>
<s:HGroup width="100%">
</s:HGroup>

</s:View>
Uma particularidade na View para editar tarefas é que ela não possui um botão para salvar
o registro. Neste caso, estamos alterando diretamente o objeto, através do recurso two
way databind.

Para concluir, temos a View com as opções da aplicação, veja:

 src/views/Opcoes.mxml
<?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="Opções">
<fx:Script>
<![CDATA[
import mx.core.FlexGlobals;
import mx.effects.Parallel;

import spark.components.ViewNavigator;
import spark.effects.Fade;
import spark.effects.Resize;
]]>
</fx:Script>

<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value
objects) here -->
</fx:Declarations>

<s:layout>
<s:VerticalLayout paddingBottom="10" paddingLeft="10"
paddingRight="10" paddingTop="10"
/>
</s:layout>

<s:VGroup horizontalAlign="center" width="100%">


<s:Button id="btnApagar" width="100%" label="Apagar
todas as tarefas">
<s:click>
<![CDATA[
hgrpApagarTudo.height = 100;
hgrpApagarTudo.visible = true;
btnApagarTarefasConcluidas.enabled = false;
]]>
</s:click>
</s:Button>
<s:HGroup id="hgrpApagarTudo" width="50%" height="0">
<s:Button id="btnApagarSim" width="100%"
label="Sim">
<s:click>
<![CDATA[

FlexGlobals.topLevelApplication.taskController.deleteAll();

FlexGlobals.topLevelApplication.tabbedNavigator.selectedIndex
= 0;
]]>
</s:click>
</s:Button>
<s:Button id="btnApagarNao" width="100%"
label="Não">
<s:click>
<![CDATA[
hgrpApagarTudo.height = 0;
hgrpApagarTudo.visible = false;
btnApagarTarefasConcluidas.enabled =
true;
]]>
</s:click>
</s:Button>
</s:HGroup>
</s:VGroup>

<s:Button id="btnApagarTarefasConcluidas" width="100%"


label="Apagar as tarefas concluidas">
<s:click>
<![CDATA[
btnApagarTarefasConcluidas.label = "Para Casa";
]]>
</s:click>
</s:Button>

</s:View>

Nas opções incluímos um botão que irá apagar todas as tarefas. Veja que esse botão abre
dois botões “Sim” e “Não”, para confirmar a operação.

Como podemos ver, mesmo em uma aplicação pequena, criamos uma estrutura em
camadas para a manipulação de dados. É claro que podemos melhorar ainda mais esta
estrutura, restringindo o uso do FlexGlobals ou então o acesso direto às propriedades do
TaskController. Neste contexto entra então outro framework muito útil para manipulação
de dados nos sistemas Flex, que é o Swiz, que será visto no próximo capítulo.
7 Flex Mobile com Swiz Framework

7.1 O que é SWIZ?


É um framework que explora dois padrões de projeto:

 Injeção de dependência
 Mediação de eventos

Através destes dois padrões, toda a arquitetura do projeto Flex torna-se mais simples e
desacoplada. Mesmo que você não entenda bem o que são estes padrões, vamos
prosseguir e mostrá-los na prática, pois é a melhor forma de entender estes dois conceitos.

 Você pode saber mais sobre Swiz em nosso livro Dominando Swiz.

7.2 Download do Swiz


5
Acesse este link e faça o download da última versão estável disponível. Após baixar o
arquivo ZIP, descompacte-o e encontre o arquivo swiz-framework-vXXX.swc, que é a lib que
será instalada no projeto.

7.3 Instalação do Swiz no projeto


Vamos criar um simples projeto que exibe dados na tela, e mostrar como o Swiz interage
com os dados da aplicação. Crie um Flex Mobile Project com o nome “FlexMobileSwiz” e
escolha o template View-Based Application. Clique no botão Finish para concluir a criação
do projeto.

Para instalar a biblioteca, basta copiar o arquivo SWC prara a pasta libs do projeto recém
criado (Figura 7.1).

5
http://swizframework.org/
Figura 7.1- Arquivo SWC instalado no projeto

Após a instalação, precisamos configurar o Swiz e isso é feito no arquivo


FlexMobileSwiz.mxml, no qual adicionamos a tag “<Swiz>” com algumas
configurações, veja:

 /FlexMobileSwiz/src/FlexMobileSwiz.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:ViewNavigatorApplication xmlns:fx="http://ns.adobe.com/mxml/2009"

xmlns:s="library://ns.adobe.com/flex/spark"

firstView="views.FlexMobileSwizHomeView"
xmlns:ns="http://swiz.swizframework.org">

<fx:Declarations>
<ns:Swiz>
<ns:beanProviders>
<!-- Aqui entrarão os Beans -->
</ns:beanProviders>
<ns:config>
<ns:SwizConfig
eventPackages="events.*"
viewPackages="views.*"/>
</ns:config>
</ns:Swiz>
</fx:Declarations>

</s:ViewNavigatorApplication>
A tag ns:Swiz configura o Swiz de forma que possamos adicionar Beans e também relaciona
o package onde encontram-se eventos da aplicação e as telas com as views. No Swiz, um
bean é um objeto que pode ser injetado em qualquer parte da view, por isso existe a
necessidade de configurar os beans e as views.

7.4 Criando uma lista de cidades


Vamos supor que estamos exibindo uma lista de cidades, de acordo com os seus
respectivos estados. Para que possamos criar uma estrutura organizada e separada em
camadas, vamos inicialmente definir uma classe chamada Cidade, que contém as
propriedades nome e estado, veja:

 /FlexMobileSwiz/src/vos/Cidade.as
package vos
{
public class Cidade
{
public function Cidade(nome:String="",estado:String="")
{
this.nome = nome;
this.estado = estado;
}

public var nome:String;


public var estado:String;

}
}

Agora, vamos criar a classe CidadeController, no package classes. Esta classe será
responsável em gerenciar os dados relativos a cidade, fazendo com que toda a lógica de
negócios ocorra nesta classe, conforme já foi visto na classe TaskController do capítulo
anterior.

/FlexMobileSwiz/src/classes/CidadeController.as
package classes
{
import mx.collections.ArrayList;

import vos.Cidade;

public class CidadeController


{
[Bindable]
public var cidades:ArrayList;

public function CidadeController()


{

[PostConstruct]
public function OnPostConstruct():void
{
cidades = new ArrayList();
cidades.addItem(new Cidade("Rio de
Janeiro","RJ"));
cidades.addItem(new Cidade("Petrópolis","RJ"));
cidades.addItem(new Cidade("Teresópolis","RJ"));
cidades.addItem(new Cidade("São Paulo","SP"));
cidades.addItem(new Cidade("Santos","SP"));
cidades.addItem(new Cidade("Belo
Horizonte","MG"));
cidades.addItem(new Cidade("Contagem","MG"));
}
}
}

O que criamos até o momento na classe CidadeController foi a variável cidades que é um
ArrayList da classe cidade. Este ArrayList é preenchido no método OnPostConstruct,
que usa a metadata [PostConstruct] do Swiz. Isso significa que o método
OnPostConstruct será executado assim que todas as referências dentro do Swiz estiverem
realizadas. Em resumo, é mais seguro instanciar as variáveis que serão usadas pelo swiz
assim que tudo estiver pronto para ele.

Com o controller parcialmente pronto, já podemos configurar o Swiz para que possa usá-lo
como uma bean. Volte ao arquivo FlexMobileSwiz.mxml, e adicione o CidadesController da
seguinte forma:

/FlexMobileSwiz/src/FlexMobileSwiz.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:ViewNavigatorApplication xmlns:fx="http://ns.adobe.com/mxml/2009"

xmlns:s="library://ns.adobe.com/flex/spark"

firstView="views.FlexMobileSwizHomeView"

xmlns:ns="http://swiz.swizframework.org"
xmlns:classes="classes.*">
<fx:Declarations>
<ns:Swiz>

<ns:beanProviders>
<ns:BeanProvider>
<!-- Aqui entrarão os Beans -->
<classes:CidadeController
id="cidadeController"/>
</ns:BeanProvider>
</ns:beanProviders>

<ns:config>
<ns:SwizConfig
eventPackages="events.*"
viewPackages="views.*"/>
</ns:config>

</ns:Swiz>
</fx:Declarations>

</s:ViewNavigatorApplication>

No BeanProviders do Swiz adicionamos a seguinte linha:


<classes:CidadeController id="cidadeController"/>

Esta é a instância da classe CidadeController, e será usada e toda a aplicação. Através do


Swiz, iremos injetar (daí o termo injeção de dependência) esta instância em diversas telas e
classes do nosso sistema e com isso não precisaremos mais usar o
“mx.core.FlexGlobals.topLevelApplication”. Ao injetarmos esta instância, estaremos
trabalhando com Flex e Swiz do jeito correto, sem gerar dependências entre as telas do
sistema.

Com a classe CidadeController devidamente configurada no BeanProvider, podemos criar a


lista de cidades na primeira view :

 /FlexMobileSwiz/src/views/FlexMobileSwizHomeView.mxml
<?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="HomeView">

<fx:Script>
<![CDATA[
import classes.CidadeController;

[Inject]
[Bindable]
public var cidadeController:CidadeController;

]]>
</fx:Script>

<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value
objects) here -->
</fx:Declarations>

<s:List width="100%" height="100%"


dataProvider="{cidadeController.cidades}"
>
<s:itemRenderer>
<fx:Component>
<s:IconItemRenderer labelField="nome"
messageField="estado"/>
</fx:Component>
</s:itemRenderer>
</s:List>

</s:View>

Nesta view, criamos uma variável chamada cidadeController, que propositalmente tem o
mesmo nome que a variável criada no BeanProvider. Esta variável criada recebe a metatag
[Inject] que é própria do Swiz, e indica que a instância da variável será injetada pela
instância que está no BeanProvider.

Com isso, ao criar o component List, usamos como dataProvider a variável cidades
(que é um ArrayList), que conterá os objetos do tipo cidade. O resultado é exibido a seguir:
Figura 7.2 - Dados de uma List através do Swiz

7.5 Criando um filtro


Agora vamos criar um filtro que irá selecionar as cidades de acordo com o estado. Em um
nível mais simples, criamos uma lista com os quatro estados criados e ao selecionar o item
desta lista, nós realizamos o filtro. Veja que queremos apenas mostrar como utilizar o Swiz
para deixar o processamento do filtro apenas no controller. Nosso objetivo aqui não é criar
o melhor tipo de filtro existente.
Primeiro, alteramos o CidadeController da seguinte forma:

 /FlexMobileSwiz/src/classes/CidadeController.as
package classes
{
import mx.collections.ArrayList;

import vos.Cidade;

public class CidadeController


{
[Bindable]
public var cidades:ArrayList;

[Bindable]
public var allCidades:ArrayList;

public function CidadeController()


{

[PostConstruct]
public function OnPostConstruct():void
{
allCidades = new ArrayList();
allCidades.addItem(new Cidade("Rio de
Janeiro","RJ"));
allCidades.addItem(new
Cidade("Petrópolis","RJ"));
allCidades.addItem(new
Cidade("Teresópolis","RJ"));
allCidades.addItem(new Cidade("São Paulo","SP"));
allCidades.addItem(new Cidade("Santos","SP"));
allCidades.addItem(new Cidade("Belo
Horizonte","MG"));
allCidades.addItem(new Cidade("Contagem","MG"));

cidades = allCidades;
}

public function filter(estado:String):void


{
var filterCidades : ArrayList = new ArrayList();

for each (var c:Cidade in allCidades.source)


{
if (c.estado == estado)
{
filterCidades.addItem(c);
}
}

cidades = null;
cidades = filterCidades;

}
}

Criamos o método filter que recebe como parâmetro a sigla do estado. Neste método, é
feito um foreach na variável allCidades, que sempre armazena todas as cidades
cadastradas, e se o estado for o mesmo, armazenamos a cidade na variável filterCidades.
Depois do foreach atribuímos o array de filterCidades ao array cidades, que é o array
principal do controller, na qual o componente list está utilizando como dataProvider.
Lembre-se que a funcionalidade de filtro é apenas um exemplo básico visando o
entendimento do framework Swiz.

Agora vamos programar a view, que contém o novo código:

 /FlexMobileSwiz/src/views/FlexMobileSwizHomeView.mxml
<?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="HomeView">

<fx:Script>
<![CDATA[
import classes.CidadeController;

[Inject]
[Bindable]
public var cidadeController:CidadeController;

]]>
</fx:Script>

<s:actionContent>
<s:CalloutButton id="filtrarCallout" label="Filtrar">
<s:List id="filtrarList">
<s:dataProvider>
<s:ArrayList>
<fx:String>MG</fx:String>
<fx:String>RJ</fx:String>
<fx:String>SP</fx:String>
<fx:String>ES</fx:String>
</s:ArrayList>
</s:dataProvider>
<s:change>
<![CDATA[

filtrarCallout.closeDropDown();

cidadeController.filter(filtrarList.selectedItem);
]]>
</s:change>
</s:List>
</s:CalloutButton>
</s:actionContent>

<s:List width="100%" height="100%"


dataProvider="{cidadeController.cidades}"
>
<s:itemRenderer>
<fx:Component>
<s:IconItemRenderer labelField="nome"
messageField="estado"/>
</fx:Component>
</s:itemRenderer>
</s:List>

</s:View>

Todo o novo código está no actionContent da View, que determina a área a direta do
cabeçalho da View. Usamos o Callout Button para criar um botão que, quando clicado,
exibe um “balão”. Neste balão, incluímos uma lista e quando selecionamos um item desta
lista, realizamos o filtro.

Veja que o filtro é chamado no evento change da list que está no Callout Button. Ao chamar
o método filter, atualizamos a referência da variável cidadeController.cidades,
que automaticamente atualiza o list principal.
Figura 7.3 - CalloutButton e lista de filtro por estado

7.6 Refatorando a lista de estados


Dando prosseguimento no entendimento do Swiz, podemos melhorar a lista de estados de
uma cidade, criando as classes Estado e EstadoController, veja:

/FlexMobileSwiz/src/vos/Estado.as
package vos
{
[Bindable]
public class Estado
{
public function Estado(nome:String="",sigla:String="")
{
this.nome = nome;
this.sigla = sigla;
}

public var nome:String;


public var sigla:String;

}
}

/FlexMobileSwiz/src/classes/EstadoController.as
package classes
{
import mx.collections.ArrayList;

import vos.Estado;

public class EstadoController


{
[Bindable]
public var estados:ArrayList;

public function EstadoController()


{
}

[PostConstruct]
public function OnPostConstruct():void
{
estados = new ArrayList();
estados.addItem(new Estado("São Paulo","SP"));
estados.addItem(new Estado("Rio de Janeiro","RJ"));
estados.addItem(new Estado("Minas Gerais","MG"));
estados.addItem(new Estado("Espirito Santo","ES"));

public function getEstadoBySigla(sigla:String):Estado


{
for each(var e:Estado in estados.source)
{
if (e.sigla == sigla)
return e;
}
return null;
}

}
}

Quando criamos a lista de cidades, veja que adicionamos os estados manualmente. Agora,
como estamos criando uma lista de estados, precisamos alterar a lista de cidades para que
cada cidade possua uma instância de um objeto estado. Conseguimos isso através do
método getEstadoBySigla, veja:

 /FlexMobileSwiz/src/classes/CidadeController.as
package classes
{
import mx.collections.ArrayList;

import vos.Cidade;

public class CidadeController


{
[Bindable]
public var cidades:ArrayList;

[Bindable]
public var allCidades:ArrayList;

[Inject]
public var estadoController:EstadoController;

public function CidadeController()


{

[PostConstruct]
public function OnPostConstruct():void
{

allCidades = new ArrayList();


allCidades.addItem(new Cidade("Rio de
Janeiro",estadoController.getEstadoBySigla("RJ")));
allCidades.addItem(new
Cidade("Petrópolis",estadoController.getEstadoBySigla("RJ")));
allCidades.addItem(new
Cidade("Teresópolis",estadoController.getEstadoBySigla("RJ")));
allCidades.addItem(new Cidade("São
Paulo",estadoController.getEstadoBySigla("SP")));
allCidades.addItem(new
Cidade("Santos",estadoController.getEstadoBySigla("SP")));
allCidades.addItem(new Cidade("Belo
Horizonte",estadoController.getEstadoBySigla("MG")));
allCidades.addItem(new
Cidade("Contagem",estadoController.getEstadoBySigla("MG")));

cidades = allCidades;
}

public function filter(sigla:String):void


{
var filterCidades : ArrayList = new ArrayList();

for each (var c:Cidade in allCidades.source)


{
if (c.estado.sigla == sigla)
{
filterCidades.addItem(c);
}
}

cidades = null;
cidades = filterCidades;

}
}
}

A classe CidadeController sofreu alterações para que possamos usar a lista de estados de
EstadoController. Primeiro, adicionamos a classe EstadoConroller, e usamos a metadata
[Inject] para que a instância de EstadoController seja injetada na classe. Com isso já
sabemos que EstadoController deve estar no Beam do Swiz no mxml principal da aplicação.
Quando criamos as cidades, usamos o método getEstadoBySigla repassando a sigla do
estado que está previamente criada. Neste momento, o objeto “cidade”, ao invés de
possuir a string “estado”, possui uma instância para um objeto do tipo “Estado”, e a partir
deste objeto podemos acessar o nome do estado ou a sigla do estado.

Na classe Cidade, vamos criar uma propriedade chamada “siglaEstado”, que será usada na
lista de cidades previamente criada:
/FlexMobileSwiz/src/vos/Cidade.as
package vos
{
[Bindable]
public class Cidade
{
public function Cidade(nome:String,estado:Estado)
{
this.nome = nome;
this.estado = estado;
}

public var nome:String;


public var estado:Estado;

public function get siglaEstado():String


{
return estado.sigla;
}

}
}

Não podemos esquecer de adicionar o bean de EstadosController na configuração do Swiz,


da seguinte forma:

/FlexMobileSwiz/src/FlexMobileSwiz.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:ViewNavigatorApplication xmlns:fx="http://ns.adobe.com/mxml/2009"

xmlns:s="library://ns.adobe.com/flex/spark"

firstView="views.FlexMobileSwizHomeView"

xmlns:ns="http://swiz.swizframework.org"
xmlns:classes="classes.*">

<fx:Declarations>
<ns:Swiz>

<ns:beanProviders>
<ns:BeanProvider>
<classes:EstadoController id="estadoController"/>
<classes:CidadeController id="cidadeController"/>
</ns:BeanProvider>
</ns:beanProviders>

<ns:config>
<ns:SwizConfig
eventPackages="events.*"
viewPackages="views.*"/>
</ns:config>

</ns:Swiz>
</fx:Declarations>

</s:ViewNavigatorApplication>

Na tela onde exibimos as cidades em uma lista, usamos agora a variável “siglaEstado” para
mostrar o estado de cada cidade, e também usamos a própria lista de estados de
estadosController para exibir a lista de estados para filtro.

/FlexMobileSwiz/src/views/FlexMobileSwizHomeView.mxml
<?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="HomeView">

<fx:Script>
<![CDATA[
import classes.CidadeController;
import classes.EstadoController;

[Inject]
[Bindable]
public var cidadeController:CidadeController;

[Inject]
[Bindable]
public var estadoController:EstadoController;

]]>
</fx:Script>

<s:actionContent>
<s:CalloutButton id="filtrarCallout" label="Filtrar">
<s:List id="filtrarList"
dataProvider="{estadoController.estados}">
<s:change>
<![CDATA[
filtrarCallout.closeDropDown();

cidadeController.filter(filtrarList.selectedItem.sigla);
]]>
</s:change>
<s:itemRenderer>
<fx:Component>
<s:IconItemRenderer
labelField="sigla"/>
</fx:Component>
</s:itemRenderer>
</s:List>
</s:CalloutButton>
</s:actionContent>

<s:List width="100%" height="100%"


dataProvider="{cidadeController.cidades}"
>
<s:itemRenderer>
<fx:Component>
<s:IconItemRenderer labelField="nome"
messageField="siglaEstado"/>
</fx:Component>
</s:itemRenderer>
</s:List>

</s:View>

7.7 Porque usar SWIZ?


Uma das maiores vantagens do Swiz é poder prover um acesso rápido e global a variáveis
que são fundamentais na aplicação. Por exemplo, quando estamos trabalhando com a lista
de estados de uma cidade, a instância desta lista está no Bean sempre, é de lá que pegamos
as informações. Isso significa que se atualizarmos esta lista ela será atualizada em todas as
partes do sistema.

Por exemplo, vamos criar um item de menu “adicionar estado”. Isso será feito na View
principal, com o seguinte código:

/FlexMobileSwiz/src/views/FlexMobileSwizHomeView.mxml

<s:viewMenuItems>
<s:ViewMenuItem label="Adicionar Estado"

click="{navigator.pushView(views.AdicionarEstado)}"
/>
<s:ViewMenuItem label="Adicionar Cidade"/>
</s:viewMenuItems>

Agora criamos a view AdicionarEstado.mxml com o seguinte código:

/FlexMobileSwiz/src/views/AdicionarEstado.mxml
<?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="Adicionar Estado">

<s:navigationContent>
<s:Button label="Voltar" click="{navigator.popView()}"/>
</s:navigationContent>

<fx:Script>
<![CDATA[
import classes.EstadoController;

import vos.Estado;

[Inject]
[Bindable]
public var estadoController:EstadoController;

[Bindable]
public var estado:Estado = new Estado();

]]>
</fx:Script>

<s:layout>
<s:FormLayout paddingBottom="10" paddingLeft="10"
paddingRight="10" paddingTop="10"
gap="20"
/>
</s:layout>

<s:TextInput prompt="Nome" width="100%"


text="@{estado.nome}"/>
<s:TextInput prompt="Sigla" width="100%"
text="@{estado.sigla}"/>

<s:Button label="Adicionar" width="100%">


<s:click>
<![CDATA[
estadoController.addEstado(estado);
navigator.popView();
]]>
</s:click>
</s:Button>

</s:View>

Nesta view, criamos um formulário que adiciona um estado utilizando o método


addEstado do estadoController. Veja que, como estadoController está injetado, ele é a
instância “viva” do Bean configurado no mxml principal do projeto. Isso significa que
quando adicionarmos um item nesta lista, a lista de estadoController.estados
será atualizada para todas as telas que a usam, automaticamente. Com esta vantagem, não
precisamos nos preocupar em atualizar todas as listas caso um item seja adicionado.

O mesmo acontece com o cadastro de cidades, que veremos a seguir. Ao adicionar um


estado, o combo de estados do formulário de cadastro de cidades será automaticamente
atualizado, veja:

/FlexMobileSwiz/src/views/AdicionarCidade.mxml
<?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="Adicionar Cidade">

<s:navigationContent>
<s:Button label="Voltar" click="{navigator.popView()}"/>
</s:navigationContent>

<fx:Script>
<![CDATA[
import classes.CidadeController;
import classes.EstadoController;

import vos.Cidade;
import vos.Estado;

[Inject]
[Bindable]
public var estadoController:EstadoController;

[Inject]
[Bindable]
public var cidadeController:CidadeController;

[Bindable]
public var cidade:Cidade = new Cidade();

]]>
</fx:Script>

<s:layout>
<s:FormLayout paddingBottom="10" paddingLeft="10"
paddingRight="10" paddingTop="10"
gap="20"
/>
</s:layout>

<s:TextInput prompt="Nome" width="100%"


text="@{cidade.nome}"/>

<s:SpinnerListContainer width="100%">
<s:SpinnerList labelField="nome"
dataProvider="{estadoController.estados}"
selectedItem="@{cidade.estado}"
width="100%"
/>
</s:SpinnerListContainer>
<s:Button label="Adicionar" width="100%">
<s:click>
<![CDATA[
cidadeController.addCidade(cidade);
navigator.popView();
]]>
</s:click>
</s:Button>

</s:View>

Após criar o cadastro de cidades, experimente criar uma cidade, depois um estado e volte
na tela de cadastro de cidades. Veja que o recém estado criado está na lista e foi adicionado
automaticamente, já que está utilizando o Swiz para injetar a instância do Bean nas telas da
aplicação.

Através desta aplicação, concluímos o nosso estudo básico sobre o Swiz, que inclusive
apresenta recursos mais avançados, mas que não serão abordados nesta obra. Veja que o
uso desse pequeno e robusto framework agiliza como um todo a manipulação de dados de
uma aplicação Flex, seja ela web, mobile ou desktop. Ou seja, se você dominar o Swiz,
poderá utilizá-lo sempre em seus projetos Flex, para qualquer tipo de plataforma.
8 Banco de dados SQLite
SQLite é um banco de dados relacional, baseado no padrão SQL92 que contém a maioria
dos comandos SQL padrões, tais como insert, delete, select, entre outros.

Usar SQL em dispositivos mobile é uma forma de ter um melhor acesso a dados dentro da
sua aplicação, podendo efetuar nativamente consultas sqls para que possa retornar dados
de forma mais rápida e concisa. No capítulo 7, criamos uma consulta no array de cidades
para que retornassem todas as cidades dado um estado. Através do comando for fizemos
uma busca item a item, o que com certeza não é o melhor solução, principalmente quando
a quantidade de itens aumenta ou a complexidade do filtro vai além de uma simples
propriedade. Por exemplo, como fazer para selecionar todas as cidades de um estado que
possuem uma população maior que X e que a quantidade de pessoas do sexo masculino
seja maior que do sexo feminino? Este é apenas um pequeno exemplo de como a SQL irá
ajudar nesta questão.

Quem programa em Flex na Web, sabe que o Flex em si não acessa o banco de dados. É
feita uma requisição a um servidor WEB e este servidor é responsável em acessar o banco
de dados. Isso requer uma conexão ativa com a internet e isso é um pouco óbvio quando
acessamos um sistema flex de um browser.

Mas quando usamos dispositivos mobile não temos como garantir que este estará 100%
conectado na Internet. Ou seja, o nosso sistema deve funcionar também quando o celular
está offline e é por isso que usamos SQLite.

Ao contrário do MySql, PostgreSQL, Oracle, SQLServer, etc, o SQLite não precisa ser
instalado no dispositivo, e todo o banco de dados é armazenado em apenas um arquivo.
Por isso ele não é um banco de dados para registrar milhões de registros, mas sim para
prover um acesso melhor a dados em dispositivos com recursos mais fracos. Ele é ideal para
mobile, e se você quer saber mais sobre SQLite, acesse www.sqlite.org.

Como não é preciso instalar o banco de dados e ele é apenas um arquivo no disco, o que
precisamos para trabalhar com o SQLite é que a tecnologia usada tenha suporte a ela.
Neste caso, o Adobe Air que é a base do desenvolvimento de sistemas flex mobile possui
este suporte nativamente. Não é preciso instalar nada (a o invés do Swiz que precisamos do
SWC), basta instanciar o banco e usar.

Resumindo, temos os seguintes passos:


1) Crie uma referência ao arquivo SQLite. Isso é feito pela classe “File” do Adobe Air
2) Crie uma conexão através da classe SQLConnection
3) Abra a conexão com o banco de dados
4) Especifique o SQL a ser executado
5) Execute a SQL

8.1 Conectando no banco de dados


Crie um projeto mobile (TesteSqlite) e adicione um botão chamado “Conectar”. Ele irá criar
a conexão com o banco e também criará uma tabela chamada “Estados”.

/TesteSqlite/src/views/TesteSqliteHomeView.mxml
<?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="HomeView">

<fx:Script>
<![CDATA[

/**
* Instância da conexão com o banco de dados
*/
public var sqlConn:SQLConnection;

protected function OnConectarClick(event:MouseEvent):void


{
//Arquivo do banco de dados SQLite
var dbFileInstance:File =
File.applicationStorageDirectory.resolvePath("Teste.sqlite");

this.sqlConn = new SQLConnection();

//Eventos para o que vai aocntecer ao abrir a conexao

this.sqlConn.addEventListener(SQLEvent.OPEN,OnOpenConnection);

this.sqlConn.addEventListener(SQLErrorEvent.ERROR,OnOpenConnec
tionError);

//tenta abrir a conexao (abrir o arquivo sqlite)


this.sqlConn.open(dbFileInstance);
}

protected function
OnOpenConnectionError(event:SQLErrorEvent):void
{
//ERRO
this.btnOpenConnection.label = " Error ";
trace("Erro ao abrir a conexão! Mensagem: " +
event.error.message);
}

protected function OnOpenConnection(event:SQLEvent):void


{
/* statement para criar a tabela */
var sql:SQLStatement = new SQLStatement();

/*conexao com o banco*/


sql.sqlConnection = this.sqlConn;

/* sql a ser executada */


sql.text = "CREATE TABLE IS NOT EXISTS estados ( id
INTEGER PRIMARY KEY AUTOINCREMENT, nome TEXT, sigla TEXT)";

/* Método executado caso o sql seja executado com


sucesso */

sql.addEventListener(SQLEvent.RESULT,OnCreateTableResult);

/* Método executado caso o sql contenha erros */

sql.addEventListener(SQLErrorEvent.ERROR,OnCreateTableError);

/* executa a sql*/
sql.execute();
}

protected function OnCreateTableResult(event:SQLEvent):void


{
// TODO Auto-generated method stub
this.btnOpenConnection.label = "OK";
}

protected function
OnCreateTableError(event:SQLErrorEvent):void
{
// TODO Auto-generated method stub
this.btnOpenConnection.label = " Error ";
trace("Error on create table");
}

]]>
</fx:Script>

<s:Button id="btnOpenConnection" width="100%" label=" Conectar "


click="OnConectarClick(event)"/>

</s:View>

Neste código criamos em  a variável sqlConn, que representa a conexão com o banco
de dados SQLite. Através dele poderemos executar consultas SQL. Para isso, precisamos
fornecer um caminho válido de um arquivo, e fazemos através da classe File do Adobe Air
(em ). Em  usamos o método open para abrir a conexão. Veja que antes disso já
adicionamos um evento que será executado se a abertura do banco for realizada com
sucesso. Quando o método OnOpenConnection for executado, já temos certeza que o
banco de dados foi aberto com sucesso e está pronto para o seu uso. Em , criamos um
SQLStatement, que é a representação de um comando SQL a ser executado. Este
comando é definido pela propriedade text. Neste caso, o comando SQL cria uma tabela
chamada “estados” com os campos id, nome e sigla. A criação é realizada em , e no caso
da sql ser executada com sucesso, o método OnCreateTableResult é chamado.

8.2 Acesso ao banco de dados


Através de uma ferramenta para visualizar um banco de dados SQLite, como o “SQLite
6
Database Browser ”, podemos acessar o arquivo .sqlite e abrir as tabelas para conferir se a
tabela “estados” foi criada. O Flex criou o arquivo “Teste.sqlite” nesta pasta:

C:\Users\<seu_usuario>\AppData\Roaming\TesteSQLite\LocalStore\

O resultado é conferido na Figura 8.1.

6
http://www.baixaki.com.br/site/dwnld75085.htm
Figura 8.1 - Banco de dados sqlite

8.3 Inserindo dados


Para inserir dados no banco de dados SQLite, podemos usar o comando INSERT do padrão
SQL, necessitando apenas informar os dados que serão gravados. Após o botão conectar,
vamos criar dois campos (nome e sigla) e o botão Add, veja:

 /TesteSqlite/src/views/TesteSqliteHomeView.mxml
<?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="HomeView">

<s:layout>
<s:VerticalLayout paddingTop="5" paddingBottom="5"
paddingLeft="5"
paddingRight="5"
gap="5"/>
</s:layout>

<fx:Script>
<![CDATA[
import mx.rpc.events.ResultEvent;

/**
* Instância da conexão com o banco de dados
*/
public var sqlConn:SQLConnection;

protected function
OnConectarClick(event:MouseEvent):void
{
//Arquivo do banco de dados SQLite
var dbFileInstance:File =
File.applicationStorageDirectory.resolvePath("Teste.sqlite");

this.sqlConn = new SQLConnection();

//Eventos para o que vai aocntecer ao abrir


a conexao

this.sqlConn.addEventListener(SQLEvent.OPEN,OnOpenConnection);

this.sqlConn.addEventListener(SQLErrorEvent.ERROR,OnOpenConnec
tionError);

//tenta abrir a conexao (abrir o arquivo


sqlite)
this.sqlConn.open(dbFileInstance);

protected function
OnOpenConnectionError(event:SQLErrorEvent):void
{
//ERRO
this.btnOpenConnection.label = " Error ";
trace("Erro ao abrir a conexão! Mensagem:
" + event.error.message);
}

protected function
OnOpenConnection(event:SQLEvent):void
{
/* statement para criar a tabela */
var sql:SQLStatement = new SQLStatement();

/*conexao com o banco*/


sql.sqlConnection = this.sqlConn;

/* sql a ser executada */


sql.text = "CREATE TABLE IF NOT EXISTS
estados ( id INTEGER PRIMARY KEY AUTOINCREMENT, nome TEXT, sigla
TEXT)";
/* Método executado caso o sql seja
executado com sucesso */

sql.addEventListener(SQLEvent.RESULT,OnCreateTableResult);

/* Método executado caso o sql contenha


erros */

sql.addEventListener(SQLErrorEvent.ERROR,OnCreateTableError);

/* executa a sql*/
sql.execute();
}

protected function
OnCreateTableResult(event:SQLEvent):void
{
// TODO Auto-generated method stub
this.btnOpenConnection.label = "OK";
}

protected function
OnCreateTableError(event:SQLErrorEvent):void
{
// TODO Auto-generated method stub
this.btnOpenConnection.label = " Error ";
trace("Error on create table");
}

protected function
OnAdicionarClick(event:MouseEvent):void
{
/* statement para criar a tabela */
var sql:SQLStatement = new SQLStatement();

/*conexao com o banco*/


sql.sqlConnection = this.sqlConn;

/*sql a ser executado*/


sql.text = "INSERT INTO estados
(nome,sigla) VALUES (:nome,:sigla)";

sql.parameters[":nome"] = txtNome.text;
sql.parameters[":sigla"] = txtSigla.text;

sql.execute(-1,new
Responder(OnAdicionarResult,OnAdicionarErrorResult));
}

private function
OnAdicionarResult(result:SQLResult):void
{
txtNome.text = "";
txtSigla.text = "";
}

private function
OnAdicionarErrorResult(error:SQLError):void
{
btnAdd.label = "Error";

]]>
</fx:Script>

<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value
objects) here -->
</fx:Declarations>

<s:Button id="btnOpenConnection" width="100%" label=" Conectar


" click="OnConectarClick(event)"/>

<s:TextInput id="txtNome" width="100%" prompt="nome"/>


<s:TextInput id="txtSigla" width="100%" prompt="sigla"/>
<s:Button id="btnAdd" width="100%" label=" adicionar"
click="OnAdicionarClick(event)"/>

</s:View>

Agora criamos um vertical layout (para que os campos fiquem um abaixo do outro), e
adicionamos duas caixas de texto e um botão. As caixas de texto correspondem aos campos
sigla e nome. O método executado quando clicamos no botão “adicionar” é este:

/TesteSqlite/src/views/TesteSqliteHomeView.mxml
protected function OnAdicionarClick(event:MouseEvent):void
{
/* statement para criar a tabela */
var sql:SQLStatement = new SQLStatement();
/*conexao com o banco*/
sql.sqlConnection = this.sqlConn;

/*sql a ser executado*/


sql.text = "INSERT INTO estados (nome,sigla) VALUES
(:nome,:sigla)";

sql.parameters[":nome"] = txtNome.text;
sql.parameters[":sigla"] = txtSigla.text;

sql.execute(-1,new
Responder(OnAdicionarResult,OnAdicionarErrorResult));

private function OnAdicionarResult(result:SQLResult):void


{
txtNome.text = "";
txtSigla.text = "";
}

private function OnAdicionarErrorResult(error:SQLError):void


{
btnAdd.label = "Error";
}

Veja que criamos um SQLStatement e referenciamos a conexão SQL, que foi feita no
primeiro botão “conectar”. Ou seja, você precisa inicialmente clicar no botão conectar para
somente depois adicionar um registro. A SQL que será executada é um insert comum, com
os parâmetros sendo repassados através da propriedade parameters. No método execute,
criamos um Responder que irá executar dois métodos, dependendo se a execução da SQL
for bem sucedida ou não. O primeiro parâmetro “-1” do execute é irrelevante neste
momento.

8.4 Retornando dados tipados


Suponha que deseje-se realizar uma consulta SQL e que cada registro retornado seja uma
classe em Action Script que representa o registro (Value Object). É possível realizar este tipo
de procedimento através do parâmetro itemClass de um SQLStatement. Veremos esta
implementação em nosso próximo capítulo.
8.5 Modo síncrono ou assíncrono
Até agora vimos como executar SQL no modo assíncrono, ou seja, definimos um método
que será chamado quando o resultado da SQL estiver pronta. Mas é possível executar uma
SQL pelo Adobe Air de forma síncrona, ou seja, podemos obter o resultado da execução da
SQL imediatamente após o comando execute, conforme o exemplo a seguir:
selectStmt = new SQLStatement();
selectStmt.sqlConnection = conn;
var sql:String = "SELECT empId, firstName, lastName, salary FROM
employees";
selectStmt.text = sql;

try
{
selectStmt.execute();
}
catch (error:SQLError)
{
status = "Error loading data";
trace("SELECT error:", error);
trace("error.message:", error.message);
trace("error.details:", error.details);
return;
}
var result:SQLResult = selectStmt.getResult();
resultsGrid.dataProvider = result.data;

Neste exemplo, utilizamos apenas o try...catch para executar a consulta, e logo após
usamos o método getResult() para obter os dados. Podemos executar nossas SQLs desta
forma, sem preocupar com performance, devendo apenas observar que operações muito
complexas poderão “travar” a tela do mobile e, as vezes, é melhor usar a forma assíncrona
exibir ao usuário uma mensagem personalizada.
9 Mobile com SQLite e Swiz
Neste capítulo vamos criar um cadastro de cidades e estados, onde tudo será carregado
inicialmente através do Swiz, que irá carregar os dados do SQLite. Usaremos a forma de
conexão síncrona, ou seja, executaremos a SQL e não iremos depender de um evento de
resposta para preenchimento de dados.

Na primeira tela poderíamos adicionar uma combobox contendo os estados já cadastrados,


para que o usuário possa selecionar o estado no qual as cidades seriam exibidas:

Figura 9.1- Tela inicial

Na barra de títulos, teríamos um botão para adicionar tanto cidades quanto estados. Ao
adicionar estados, podemos exibir uma tela semelhante a Figura 9.2.
Figura 9.2 - Inserir Estado

Na tela de inserir cidades, incluímos o combobox par relacionar um estado a uma cidade, de
acordo com a Figura 9.3.

Figura 9.3 - Inserir cidade

9.1 Configurações iniciais


Primeiro, crie o projeto “FlexCities”, selecionando File, New, Flex Mobile Project. O template
será “View-Based Application”. Após criar o projeto, você precisa copiar o arquivo swiz-
framework-vXXX.swc para a pasta libs, conforme foi visto no capítulo 7.3. Primeiro,
devemos configurar o Swiz e isso é feito no arquivo principal do projeto, o FlexCities.mxml,
veja:

/FlexCities/src/FlexCities.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:ViewNavigatorApplication
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:swiz="http://swiz.swizframework.org"
firstView="views.Home" xmlns:controllers="controllers.*">

<fx:Declarations>
<swiz:Swiz>

<swiz:beanProviders>
<swiz:BeanProvider>
<!-- Aqui entrarão os Beans -->

</swiz:BeanProvider>
</swiz:beanProviders>

<swiz:loggingTargets>
<swiz:SwizTraceTarget id="myTraceTarget" />
</swiz:loggingTargets>

<swiz:config>
<swiz:SwizConfig
eventPackages="events.*"
viewPackages="views.*"/>
</swiz:config>

</swiz:Swiz>
</fx:Declarations>

</s:ViewNavigatorApplication>

Esta é a configuração padrão para o swiz. A medida que criamos os controllers que devem
ser injetados na view, iremos adicioná-lo no <BeanProvider>.

9.2 Criando o banco de dados


Ao contrário do capítulo anterior, que criamos o banco no mxml principal do projeto, vamos
criar um controller chamado AppControler que irá criar o banco de dados e manter algumas
configurações da aplicação, veja:
/FlexCities/src/controllers/AppController.as
package controllers
{
import flash.data.SQLConnection;
import flash.data.SQLStatement;
import flash.events.Event;
import flash.events.IEventDispatcher;
import flash.events.SQLErrorEvent;
import flash.events.SQLEvent;
import flash.filesystem.File;

public class AppController extends BaseController


{
public var sqlConn:SQLConnection;

public function AppController()


{

[PostConstruct]
public function OnPostContruct():void
{
//Arquivo do banco de dados SQLite
var dbFileInstance:File =
File.applicationStorageDirectory.resolvePath("FlexCities.sqlite");

this.sqlConn = new SQLConnection();

//Eventos para o que vai aocntecer ao abrir a conexao


this.sqlConn.addEventListener(SQLEvent.OPEN,OnOpenConnection);
this.sqlConn.addEventListener(SQLErrorEvent.ERROR,OnOpenConnec
tionError);

//tenta abrir a conexao (abrir o arquivo sqlite)


this.sqlConn.open(dbFileInstance);
}

protected function OnOpenConnectionError(event:SQLErrorEvent):void


{
//ERRO
trace("Erro ao abrir a conexão! Mensagem: " +
event.error.message);
}

protected function OnOpenConnection(event:SQLEvent):void


{
this.createDB();
}

public function createDB():void


{
var sql:SQLStatement = new SQLStatement();
sql.sqlConnection = this.sqlConn;

sql.text = "CREATE TABLE IF NOT EXISTS estados ( id INTEGER


PRIMARY KEY AUTOINCREMENT, nome TEXT, sigla TEXT)";
sql.execute();

sql.text = "CREATE TABLE IF NOT EXISTS cidades ( id INTEGER


PRIMARY KEY AUTOINCREMENT, nome TEXT, idEstado INT, FOREIGN
KEY(idEstado) REFERENCES estados(id))";
sql.execute();

}
}

Em  usamos a metatag [PostConstruct] para que o método OnPostConstruct seja


executado assim que o Swiz estiver pronto. Quando isso acontecer, abrimos (ou criamos) o
arquivo “Flexcities.sqlite” e depois usamos a classe SQLConnection para abrir a conexão. A
variável sqlConn é responsável em possuir a instância da conexão, e ela será usada em
todo o sistema. Sempre que precisarmos executar um SQL no banco, usaremos sqlConn
para a conexão.

Após abrir a conexão com sucesso, o método OnOpenConnection é executado e chamamos


o método createDB, que irá executar duas SQLs para criar as tabelas. Após criar o
AppControler, temos que adicioná-lo ao BeanProvider da aplicação:

/FlexCities/src/FlexCities.mxml
...
<swiz:beanProviders>
<swiz:BeanProvider>
<!-- Aqui entrarão os Beans -->
<controllers:AppController id="appController"/>
</swiz:BeanProvider>
</swiz:beanProviders>
...
Com as tabelas criadas, podemos partir para a tela de inclusão de estados. A view principal,
que chamaremos de Home.mxml (faça o rename no Flash Builder), conterá um botão
(CalloutButton) no qual podemos adicionar cidades e estados:

/FlexCities/src/views/Home.mxml
<?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="FlexCities">

<s:actionContent>
<s:CalloutButton label="+">
<s:VGroup
paddingLeft="5" paddingBottom="5"
paddingRight="5" paddingTop="5"
>
<s:Button label="+ Cidade"
click="{navigator.pushView(InserirCidade)}"/>
<s:Button label="+ Estado"
click="{navigator.pushView(InserirEstado)}"/>
</s:VGroup>
</s:CalloutButton>
</s:actionContent>

</s:View>

9.3 Cadastrando estados


Precisamos inicialmente criar a tela para inserir estados, na qual chamaremos de
InserirEstado.mxml. Lembre-se que esta tela é uma View e está no package views. Ao
criarmos a tela, precisamos criar também a classe EstadosController, que irá gerenciar
todos os dados da tabela estados, e criar a classe Estado, que representa o um registro de
estado.

/FlexCities/src/vos/Estado.as
package vos
{
[Bindable]
public class Estado
{
public function Estado()
{
}
public var id:int;
public var nome:String;
public var sigla:String;

}
}

/FlexCities/src/controllers/EstadoController.as
package controllers
{
import flash.data.SQLResult;
import flash.data.SQLStatement;

import mx.collections.ArrayCollection;

import vos.Estado;

public class EstadoController extends BaseController


{

public function EstadoController()


{

[Bindable]
public var dataProvider:ArrayCollection;

[Bindable]
public var item:Estado;

[Inject]
public var appController:AppController;

[PostConstruct]
public function OnPostConstruct():void
{
this.getAll();
this.item = new Estado();
}

public function getAll():void


{
var sql:SQLStatement = new SQLStatement();
sql.sqlConnection = appController.sqlConn;
sql.itemClass = Estado;
sql.text = "SELECT * FROM estados";
sql.execute();

var result:SQLResult = sql.getResult();


if (result!=null)
this.dataProvider = new ArrayCollection(result.data);
}

public function save():void


{
var sql:SQLStatement = new SQLStatement();
sql.sqlConnection = appController.sqlConn;

if (item.id==0)
{
sql.text = "INSERT INTO estados (nome,sigla) VALUES
(:nome,:sigla)";
}
else
{

sql.parameters[":nome"] = item.nome;
sql.parameters[":sigla"] = item.sigla;

sql.execute();
getAll();
item = new Estado();
}

public function getById(idEstado:int):Estado


{
// Como temos poucos estados, podemos fazer um LOOP;
for each (var e:Estado in dataProvider)
{
if (e.id == idEstado)
return e;
}
return null;
}
}
}

A classe EstadosController é usada para gerenciar estados. Criamos duas variáveis públicas
principais, chamadas de dataProvider e item, que representam, respectivamente, o
conjunto de estados e um estado único. A view irá utilizar estas variáveis constantemente.
Injetamos o controller AppController para que possamos pegar a instância da conexão com
o banco, que é a variável sqlConn.

No método OnPostConstruct, chamamos o método getAll, que irá executar uma consulta
SQL. Veja que a instância do banco de dados é obtida através de
appController.sqlConn, e que informamos o itemClass como Estado, que é a
classe que representa um registro de estado. Executamos a sql através do comando
execute e obtemos o resultado através do getResult. O resultado é atribuído a
variável dataProvider do controller.

Após o getAll, temos o método save que irá salvar o registro. Neste capítulo veremos
apenas como inserir um registro, sendo que para alterar basta implementar o comando sql
update. Após definir a sql, usamos o parâmetro parameters para informar os dados que
serão embutidos na SQL. Também “zeramos” a variável item para que os dados na view
sejam zerados também.

O método getById faz algo diferente de uma sql. É claro que você poderia fazer uma SQL
aqui, usando “SELECT * from ESTADOS where id=:id”, mas como temos poucos estados
cadastrados, fazemos um loop. Tome cuidado com este loop para um conjunto
relativamente grande de itens, mesmo porque estamos em um dispositivo mobile sem
recursos de hardware.

Após criar o controller, criamos a view, que irá usar este controller para manipulação de
dados. Crie a View InserirEstado no package views, com o seguinte código:

FlexCities/src/views/InserirEstado.mxml
<?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="Inserir Estado"
xmlns:mx="library://ns.adobe.com/flex/mx">

<s:layout>
<s:FormLayout paddingBottom="10" paddingLeft="10"
paddingRight="10" paddingTop="20"
gap="5"
/>
</s:layout>

<fx:Script>
<![CDATA[
import controllers.EstadoController;
import mx.validators.Validator;

[Inject]
[Bindable]
public var estadoController:EstadoController;

protected function
btnSalvar_clickHandler(event:MouseEvent):void
{
if (Validator.validateAll(validators).length==0)
{
estadoController.save();
navigator.popView();
}

]]>
</fx:Script>

<s:navigationContent>
<s:Button label="Voltar" click="{navigator.popView()}"/>
</s:navigationContent>

<fx:Declarations>
<fx:Array id="validators">
<mx:StringValidator id="valNome" required="true"
source="{txtNome}" property="text"
trigger="{btnSalvar}" triggerEvent="click"
/>
<mx:StringValidator id="valSigla" required="true"
source="{txtSigla}" property="text"
trigger="{btnSalvar}" triggerEvent="click"
/>
</fx:Array>

</fx:Declarations>

<s:TextInput id="txtNome" width="100%" prompt="Nome"


text="@{estadoController.item.nome}" />
<s:TextInput id="txtSigla" width="100%" prompt="Sigla"
text="@{estadoController.item.sigla}"/>
<s:Spacer height="20"/>
<s:Button id="btnSalvar" width="100%" label="Salvar"
click="btnSalvar_clickHandler(event)"/>

</s:View>
Veja que a view é relativamente simples. Em , adicionamos o estadoController, no
qual usamos para ligar os dados do formulário à variável item. Também usamos o
controller para executar o comando save, que irá persistir os dados. Após salvar, usamos o
comando popView para fechar a view e voltar para a view anterior. Lembre-se que toda
variável injetada deve estar presente no <beanproviders> da configuração do swiz.

9.4 Cadastrando cidades


Agora que inserimos alguns estados, podemos criar a tela para cadastrar cidades.
Inicialmente criamos a classe que representa um registro de cidade:

/FlexCities/src/vos/Cidade.as
package vos
{
[Bindable]
public class Cidade
{
public function Cidade()
{

public var id:int;


public var idEstado:int;
public var nome:String;
public var estado:Estado;

public function get siglaEstado():String


{
return estado.sigla;
}

}
}
Veja que a classe possui, além dos campos normais da tabela, o campo estado, que
representa uma instância do estado da cidade. A classe de controller de cidades é
apresentada a seguir:

/FlexCities/src/controllers/CidadeController.as
package controllers
{
import flash.data.SQLResult;
import flash.data.SQLStatement;

import mx.collections.ArrayCollection;

import vos.Cidade;
import vos.Estado;

public class CidadeController extends BaseController


{

[Bindable]
public var dataProvider:ArrayCollection;

[Bindable]
public var dataProviderByEstado:ArrayCollection;

[Bindable]
public var item:Cidade;

[Inject]
public var appController:AppController;

[Inject]
public var estadoController:EstadoController;

[PostConstruct]
public function OnPostConstruct():void
{
this.getAll();
this.item = new Cidade();
}

public function getAll():void


{
var sql:SQLStatement = new SQLStatement();
sql.sqlConnection = appController.sqlConn;
sql.itemClass = Cidade;
sql.text = "SELECT * FROM cidades";
sql.execute();

var result:SQLResult = sql.getResult();


if (result!=null)
{
//Para cada item do DataProvider, recuperamos
// o seu estado
for each (var c:Cidade in result.data)
{
c.estado =
estadoController.getById(c.idEstado);

this.dataProvider = new ArrayCollection(result.data);


}
}

public function save():void


{
var sql:SQLStatement = new SQLStatement();
sql.sqlConnection = appController.sqlConn;

if (item.id==0)
{
sql.text = "INSERT INTO cidades (nome,idEstado) VALUES
(:nome,:idEstado)";
}
else
{

sql.parameters[":nome"] = item.nome;
sql.parameters[":idEstado"] = item.estado.id;

sql.execute();
getAll();
item = new Cidade();
}

public function setFilterEstado(estado:Estado):void


{
var sql:SQLStatement = new SQLStatement();
sql.sqlConnection = appController.sqlConn;
sql.itemClass = Cidade;
sql.text = "SELECT * FROM cidades WHERE idEstado = :idEstado";
sql.parameters[":idEstado"] = estado.id;
sql.execute();
var result:SQLResult = sql.getResult();
for each (var c:Cidade in result.data)
{
c.estado = estado;
}
this.dataProviderByEstado = new ArrayCollection(result.data);
}

}
}

Esta classe é semelhante ao EstadoController, com algumas implementações extras.


Inicialmente criamos dois dataProviders. O primeiro contém todas as cidades enquanto que
o segundo contém cidades de um determinado estado. Usaremos este segundo
dataProvider na tela principal do sistema, pois precisamos exibir as cidades de um
determinado estado.

A view para criar cidades é a seguinte:

/FlexCities/src/views/InserirCidade.mxml
<?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="Inserir Cidade" xmlns:mx="library://ns.adobe.com/flex/mx">

<s:layout>
<s:FormLayout paddingBottom="10" paddingLeft="10"
paddingRight="10" paddingTop="20"
gap="5"
/>
</s:layout>

<fx:Script>
<![CDATA[
import controllers.CidadeController;
import controllers.EstadoController;

import mx.validators.Validator;

import vos.Estado;

[Inject]
[Bindable]
public var estadoController:EstadoController;

[Inject]
[Bindable]
public var cidadeController:CidadeController;

protected function
btnSalvar_clickHandler(event:MouseEvent):void
{
if (Validator.validateAll(validators).length==0)
{
cidadeController.save();
navigator.popView();
}

protected function GetLabelSpinner(item:Estado):String


{
return item.sigla + " - " + item.nome;
}

]]>
</fx:Script>

<s:navigationContent>
<s:Button label="Voltar" click="{navigator.popView()}"/>
</s:navigationContent>

<fx:Declarations>

<fx:Array id="validators">
<mx:StringValidator id="valNome" required="true"
source="{txtNome}" property="text"
trigger="{btnSalvar}" triggerEvent="click"
/>
</fx:Array>

</fx:Declarations>

<s:TextInput id="txtNome" width="100%" prompt="Nome"


text="@{cidadeController.item.nome}" />

<s:SpinnerListContainer width="100%">
<s:SpinnerList id="spnEstado"
dataProvider="{estadoController.dataProvider}"
labelField="nome"
width="100%"
labelFunction="GetLabelSpinner"
>
<s:change>
<![CDATA[
cidadeController.item.estado = spnEstado.selectedItem;
]]>
</s:change>
<s:creationComplete>
<![CDATA[
cidadeController.item.estado = spnEstado.selectedItem;
]]>
</s:creationComplete>
</s:SpinnerList>
</s:SpinnerListContainer>

<s:Spacer height="20"/>
<s:Button id="btnSalvar" width="100%" label="Salvar"
click="btnSalvar_clickHandler(event)"/>

</s:View>

A view de cidades possui um SpinnerList com os estados cadastrados. Por isso é necessário
injetar o estadoController nesta view para que possamos usar o seu dataProvider. Após
incluir os dois cadastros, a tela principal do sistema (Home.mxml) pode chamar estas duas
telas através do componente CallOutButton:

/FlexCities/src/views/Home.mxml
<?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="FlexCities">

<s:actionContent>
<s:CalloutButton label="+">
<s:VGroup
paddingLeft="5" paddingBottom="5"
paddingRight="5" paddingTop="5"
>
<s:Button label="+ Cidade"
click="{navigator.pushView(InserirCidade)}"/>
<s:Button label="+ Estado"
click="{navigator.pushView(InserirEstado)}"/>
</s:VGroup>
</s:CalloutButton>
</s:actionContent>

</s:View>
9.5 Finalizando o sistema
Tanto InserirCidade quanto InserirEstado executam uma popView quando um registro é
incluído, então elas voltam automaticamente para a tela Home. Agora vamos exibir uma
lista de estados na tela Home, fazendo com que possamos selecionar um estado para
acessarmos as suas respectivas cidades.

/ FlexCities/src/views/Home.mxml
<?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="FlexCities">

<fx:Script>
<![CDATA[
import controllers.CidadeController;
import controllers.EstadoController;

[Inject]
[Bindable]
public var estadoController:EstadoController;

[Inject]
[Bindable]
public var cidadeController:CidadeController;

]]>
</fx:Script>

<s:actionContent>
<s:CalloutButton label="+">
<s:VGroup
paddingLeft="5" paddingBottom="5"
paddingRight="5" paddingTop="5"
>
<s:Button label="+ Cidade"
click="{navigator.pushView(InserirCidade)}"/>
<s:Button label="+ Estado"
click="{navigator.pushView(InserirEstado)}"/>
</s:VGroup>
</s:CalloutButton>
</s:actionContent>

<s:List width="100%" height="100%"


id="lstEstados"
dataProvider="{estadoController.dataProvider}"
labelField="nome"
>
<s:change>
<![CDATA[
cidadeController.setFilterEstado(lstEstados.selectedItem);
navigator.pushView(VerCidades);
]]>
</s:change>
</s:List>

</s:View>

Inicialmente adicionamos os dois controllers, de cidades e estados. O EstadoController fica


responsável em preencher a lista de estados na view. Quando o usuário selecionar um
estado, usamos o método setFilterEstado para filtrar as cidades daquele estado
selecionado, e carregamos outra view, chamada VerCidades:

 /FlexCities/src/views/VerCidades.mxml
<?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="FlexCities">

<s:navigationContent>
<s:Button label="Voltar" click="{navigator.popView()}" />
</s:navigationContent>

<fx:Script>
<![CDATA[
import controllers.CidadeController;

[Inject]
[Bindable]
public var cidadeController:CidadeController;

]]>
</fx:Script>

<s:List width="100%" height="100%"


id="lstCidades"
dataProvider="{cidadeController.dataProviderByEstado}"
labelField="nome"
>
</s:List>
</s:View>

A view possui um List que tem como dataProvider a propriedade dataProviderByEstado,


que foi filtrada na view anterior.

Este capítulo é importante para que possamos entender que as instâncias de


cidadeController e estadoController foram criadas na configuração do swiz (Beans), e que
ficam disponíveis durante todo o sistema, para que possa ser consultado sempre. É preciso
ter cuidado para não adicionar muitos controllers na aplicação de forma que muitos dados
sejam carregados no início.
10 Interação com o dispositivo mobile
Além de possuir todo um conjunto de componentes para a criação de aplicações com o
mobile, o framework Flex também possui acesso ao dispositivo através de uma API, de
forma que seja possível realizar algumas tarefas extras, como GPS, acelerômetro, câmera,
etc.

Veremos a seguir uma lista de funcionalidades que podem ser executadas pelo Flex.
Criaremos o projeto (Flex Mobile Project) MobileAPI para ilustrar cada processo
separadamente. Todos os processos foram testados no dispositivo Sansumg Galaxy Tab,
Android 2.2. Ao criar o projeto, habilite todas as permissões de acesso tais como acesso a
câmera, GPS, etc.

Inicialmente criaremos uma lista de ações, conforme o código a seguir:

/MobileAPI/src/views/MobileAPIHomeView.mxml
<?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="HomeView">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value
objects) here -->
</fx:Declarations>

<s:navigationContent>
<!-- Vazio, para nao aparecer o botao voltar -->
</s:navigationContent>

<s:layout>
<s:VerticalLayout paddingBottom="10" paddingLeft="10"
paddingRight="10" paddingTop="10"/>
</s:layout>

<s:Button width="100%" label="Navegador nativo"/>


<s:Button width="100%" label="Gestos e Multitouch"/>
<s:Button width="100%" label="Acesso a câmera"/>
<s:Button width="100%" label="Tela"/>
<s:Button width="100%" label="Acelerômetro"/>
<s:Button width="100%" label="GPS"/>

</s:View>
10.1 StageWebView (Browser)
Este nome complicado se resume a utilização do navegador nativo do celular. Através desta
classe é possível abrir o navegador dentro da aplicação flex. O código básico para isso está
na view NavegadorNativo.mxml:

 /MobileAPI/src/views/NavegadorNativo.mxml
<?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="NavegadorNativo">

<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value
objects) here -->
</fx:Declarations>

<s:creationComplete>
<![CDATA[

var browser:StageWebView = new StageWebView();


browser.stage = this.stage;
browser.loadURL("http://www.google.com.br");
browser.viewPort = new Rectangle(0, stage.height-
height,width,height);

]]>
</s:creationComplete>

</s:View>

Neste código, criamos a variável browser que é um StageWebView. Definimos o stage do


browser como sendo o stage da aplicação e carregamos uma URL qualquer com o método
loadURL. O viewPort define a área da aplicação, que segue a regra básica descrita no
código.

Este código pode ser melhorado para que fique compatível com o resize da aplicação, caso
haja uma alteração na reorientação do mesmo. Para isso precisamos capturar o evento
resize da view e recriar novamente o viewPort, veja:

 /MobileAPI/src/views/NavegadorNativo.mxml
<?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="NavegadorNativo"
resize="{resizeHandler()}"
removing="removingHandler(event)"

>

<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -
->
</fx:Declarations>

<fx:Script>
<![CDATA[
import mx.events.ResizeEvent;

import spark.events.ViewNavigatorEvent;

public var browser:StageWebView

protected function resizeHandler():void


{
if (this.browser!=null)
this.browser.viewPort = new
Rectangle(0,this.stage.height-this.height,this.width,this.height);
}

protected function
removingHandler(event:ViewNavigatorEvent):void
{
if (this.browser!=null)
this.browser.dispose();
}

]]>
</fx:Script>

<s:creationComplete>
<![CDATA[

browser = new StageWebView();


browser.stage = this.stage;
browser.loadURL("http://www.google.com.br");
browser.viewPort = new Rectangle(0,stage.height-height,width,height);

]]>
</s:creationComplete>
</s:View>

Agora adicionamos dois eventos na view, que são correspondentes ao resize da tela e
quando a view é removida do stage. Quando clicamos no botão voltar a tela é removida
para que não atrapalhe outras telas.

10.2 Touch
Quase todos os dispositivos mobile possuem suporte a Touch, que é tocar na tela e realizar
algum tipo de ação. Usamos a classe MultiTouch para gerenciar os toques na tela. Através
dela podemos saber exatamente onde o usuário está tocando e se está realizando alguma
ação específica.

No exemplo a seguir, criamos um contador de touchs na tela, ou seja, quantas vezes o


event de TAP ocorre na tela.

/MobileAPI/src/views/TouchViewCounter.mxml
<?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="Touch">

<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -
->
</fx:Declarations>

<s:layout>
<s:VerticalLayout paddingBottom="10" paddingLeft="10"
paddingRight="10" paddingTop="10"/>
</s:layout>

<fx:Script>
<![CDATA[

[Bindable]
public var tCounter:int = 0;

public function onTouchTap(event:TouchEvent):void


{
tCounter++;
}
]]>
</fx:Script>

<s:Label text="Support Touch? {Multitouch.supportsTouchEvents}"/>


<s:Label text="Touch counter: {tCounter.toString()}"/>

<s:creationComplete>
<![CDATA[

Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT;

if (Multitouch.supportsTouchEvents)
{
this.addEventListener(TouchEvent.TOUCH_TAP, onTouchTap);
}

]]>
</s:creationComplete>

</s:View>

Neste exemplo, usamos em  o atributo Multitouch.inputMode para definir como


vai ser o método de entrada da View. Isso é necessário porque você precisa dizer a view
como ela vai interpretar um touch ou um gesto na tela. Neste caso, o valor TOUCH_POINT
diz que cada interação (toque) na tela do mobile será interpretada como um evento TOUCH
(simples toque).

Repare também que estamos analisando se o dispositivo suporta touch. Se suportar,


adicionamos o evento TouchEvent.TOUCH_TAP, que irá incrementar uma variável exibida
na tela.

No próximo exemplo usamos o TOUCH_TAP para desenhar um círculo na tela:

/MobileAPI/src/views/TouchViewClick.mxml
<?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="Touch">

<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects)
here -->
</fx:Declarations>

<fx:Declarations>
<fx:Component className="Bolinha">
<s:Ellipse width="100" height="100">
<s:fill>
<s:SolidColor color="#ff0000"/>
</s:fill>
</s:Ellipse>
</fx:Component>
</fx:Declarations>

<fx:Script>
<![CDATA[

[Bindable]
public var tCounter:int = 0;

public function onTouchTap(event:TouchEvent):void


{
tCounter++;
showBolinha(event.localX,event.localY);
}

public function showBolinha(x:int,y:int):void


{
var b:Bolinha = new Bolinha();
b.x = x-50;
b.y = y-50;
addElement(b);

]]>
</fx:Script>

<s:Label text="Support Touch? {Multitouch.supportsTouchEvents}"


x="10" y="10"/>
<s:Label text="Touch counter: {tCounter.toString()}" x="10" y="30"/>

<s:creationComplete>
<![CDATA[

Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT;

if (Multitouch.supportsTouchEvents)
{
this.addEventListener(TouchEvent.TOUCH_TAP, onTouchTap);
}
]]>
</s:creationComplete>

</s:View>

Ao desenhar o círculo, usamos as coordenadas X e Y repassadas pelo evento, e diminuímos


50 pixels para que o círculo fique localizado no centro de onde foi realizado o toque da tela.

Talvez você esteja pensando em como seria difícil usar os eventos touch para capturar um
gesto, como, por exemplo, arrastar um toque na tela para a direita. Felizmente existem
eventos específicos para esse tipo de movimento, no qual destacamos a seguir.

10.3 Gestures (Gestos)


Além do simples toque na tela temos eventos mais complexos que o Flex pode capturar.
Dentre ele temos:

10.3.1 Zoom

Você pode usar este gesto para dar Zoom em imagens e componentes. O
seu uso compreende de dois pontos abrindo ou fechando uma
determinada área.

Lembrando que configuramos o Multitouchinputmode=Touch no exemplo anterior,


precisamos agora mudar este parâmetro para GESTURE. Depois usamos o evento
GESTURE_ZOOM e a propriedade scaleX e scaleY para redimensionar o objeto.

 /MobileAPI/src/views/GesturesZoomView.mxml
<?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="GesturesZoomView">

<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects)
here -->
</fx:Declarations>

<s:creationComplete>
<![CDATA[
Multitouch.inputMode = MultitouchInputMode.GESTURE;

addEventListener(TransformGestureEvent.GESTURE_ZOOM,
function(event:TransformGestureEvent):void {
btn.scaleX *= event.scaleX;
btn.scaleY *= event.scaleY;
});

]]>
</s:creationComplete>

<s:Button label="Button" id="btn"/>

</s:View>

Ao aplicarmos o evento GESTURE_ZOOM, usamos event.scaleX para definir a diferença


de escala em relação ao último evento GESTURE. A multiplicação desta scala com a scala do
botão (o objeto) define o seu zoom.

No exemplo a seguir, apresentamos uma variação do exemplo anterior, mostrando que


podemos adicionar o evento de ZOOM diretamente no objeto, ao invés de toda a tela. Para
imagens, usamos o método tranfsormAround que promove uma transição de imagem
mais suave:

 /MobileAPI/src/views/GesturesZoomHappinessView.mxml
<?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="GesturesZoomHappinessView">

<s:layout>
<s:VerticalLayout paddingBottom="10" paddingLeft="10"
paddingRight="10"
paddingTop="10"/>
</s:layout>

<s:creationComplete>
<![CDATA[
Multitouch.inputMode = MultitouchInputMode.GESTURE;
]]>
</s:creationComplete>

<s:Image id="img" source="@Embed('assets/smile.jpg')">


<s:creationComplete>
<![CDATA[

img.addEventListener(TransformGestureEvent.GESTURE_ZOOM,
function(event:TransformGestureEvent):void {
img.transformAround(new
Vector3D(event.localX, event.localY, 0), new Vector3D(img.scaleX *
event.scaleX, img.scaleY * event.scaleY, 0));
});
]]>
</s:creationComplete>
</s:Image>

</s:View>

10.3.2 Swipe

O gesto de swipe é compreendido por passar o dedo na tela de um ponto a outro. Você já
conhece esse gesto, pois é usado quando passa fotos em um dispositivo mobile. No
exemplo a seguir, vamos ilustrar como capturar o evento de swipe.

/MobileAPI/src/views/GesturesSwipeView.mxml
<?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="GesturesZoomView">

<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value
objects) here -->
</fx:Declarations>

<s:creationComplete>
<![CDATA[

Multitouch.inputMode = MultitouchInputMode.GESTURE;

addEventListener(TransformGestureEvent.GESTURE_SWIPE,
function(event:TransformGestureEvent):void {

if (event.offsetX == 1 ) {
lbl.text = "para direta";
}
else if (event.offsetX == -1 ) {
lbl.text = "para esqueda";
}
else if (event.offsetY == 1) {
lbl.text = "para baixo";
}
else if (event.offsetY == -1) {
lbl.text = "para cima";
}

});

]]>
</s:creationComplete>

<s:Label id="lbl" x="10" y="10" color="#FF0600" fontSize="24"


fontWeight="bold" text="SWIPE"/>

</s:View>

Neste exemplo, capturamos o evento GESTURE_SWIPE e então usamos o atributo offset


para determinar a direção. Repare que adicionamos o evento na tela, mas poderíamos
adicionar o evento em um objeto qualquer, como no exemplo a seguir:

/MobileAPI/src/views/SwipeListItemRenderer.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:LabelItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"

xmlns:s="library://ns.adobe.com/flex/spark"
height="100"
>

<s:creationComplete>
Multitouch.inputMode = MultitouchInputMode.GESTURE;

addEventListener(TransformGestureEvent.GESTURE_SWIPE,
function(event:TransformGestureEvent):void {

if (event.offsetX == -1 ) {
addChild(menu);
}

});
</s:creationComplete>

<fx:Declarations>
<s:Label id="lbl" text="{data.toString()}"/>
<s:HGroup id="menu" width="{this.width}"
height="{this.height}" gap="5"
horizontalAlign="center"
verticalAlign="middle"

>
<s:Button id="btn1" label="fazer algo"/>
<s:Button id="btn2" label="fazer algo 2"/>
<s:Button id="btn3" label="close">
<s:click>
<![CDATA[
removeChild(menu);
]]>
</s:click>
</s:Button>
</s:HGroup>
</fx:Declarations>
</s:LabelItemRenderer>

/MobileAPI/src/views/GesturesSwipeListView.mxml
<?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="GesturesZoomView">

<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value
objects) here -->
</fx:Declarations>

<s:creationComplete>
<![CDATA[

Multitouch.inputMode = MultitouchInputMode.GESTURE;

]]>
</s:creationComplete>

<s:List id="lista" width="100%" height="100%"


itemRenderer="views.SwipeListItemRenderer"
>
<s:dataProvider>
<s:ArrayList>
<fx:String>Item 1</fx:String>
<fx:String>Item 2</fx:String>
<fx:String>Item 3</fx:String>
<fx:String>Item 4</fx:String>
<fx:String>Item 5</fx:String>
<fx:String>Item 6</fx:String>
<fx:String>Item 7</fx:String>
</s:ArrayList>
</s:dataProvider>
</s:List>

</s:View>

Neste código criamos um ItemRenderer que contém uma área especial chamada de menu
que é exibida se o usuário usar o swipe right. Podemos utilizar este conceito para adicionar
ações a um determinado item do componente List. Você encontra um exemplo interessante
7
dessa técnica neste vídeo .

10.4 Pan
O gesto de Pan envolve arrastar algo na tela e é realizado com com duas entradas (dois
dedos...). Através do Pan você pode alterar o X e Y de um objeto fazendo-o arrastar pela
tela. O código básico para isso é:
Multitouch.inputMode = MultitouchInputMode.GESTURE;

addEventListener(TransformGestureEvent.GESTURE_PAN,
function(event:TransformGestureEvent):void {
obj.x += event.offsetX;
obj.y += event.offsetY;
});

10.5 Rotate
O mesmo pode ser aplicado ao rotate, que usa o evento GESTURE_ROTATE quando o
usuário rotaciona os dois dedos na tela.
<s:creationComplete>
Multitouch.inputMode = MultitouchInputMode.GESTURE;

addEventListener(TransformGestureEvent.GESTURE_ROTATE,
function(event:TransformGestureEvent):void {

7
http://www.youtube.com/watch?v=c2EopmBbpMY
img.transformAround(new Vector3D(img.width/2, img.height/2, 0),
null, new Vector3D(0, 0, img.rotationZ + event.rotation));
});
</s:creationComplete>

No exemplo acima, o objeto img é uma imagem qualquer.

10.6 Câmera
Se o dispositivo mobile possuir uma câmera, é claro que você pode usá-la em suas
aplicações Flex. Existem duas formas distintas de acessar a câmera do mobile. Pode
adicionar a câmera automaticamente na aplicação ou então pode-se tirar uma foto pelo
sistema nativo do dispositivo.

10.7 Acesso à câmera


O acesso à câmera do dispositivo é feito da mesma forma que é feito no desktop (Adobe
Air). Criamos um UIComponent e depois usamos a classe Camera para realizar o acesso.
Exemplificamos esse processo neste exemplo:

 /MobileAPI/src/views/AcessoDiretoCamera.mxml
<?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="Cadastro Usuario"
xmlns:mx="library://ns.adobe.com/flex/mx">

<s:layout>
<s:VerticalLayout paddingBottom="10" paddingLeft="10"
paddingRight="10" paddingTop="10"/>
</s:layout>

<fx:Script>
<![CDATA[
public var videoCam:Video;
]]>
</fx:Script>

<s:creationComplete>
if (Camera.isSupported)
{
videoCam = new Video(300, 300);
uic.addChild(videoCam);
var c:Camera = Camera.getCamera();
c.setMode(300, 300, 10);
videoCam.attachCamera(c);
}
</s:creationComplete>

<s:TextInput width="100%" prompt="Nome"/>

<s:HGroup width="100%">
<s:Label text="Foto" />

<s:CalloutButton id="cb" label="Tirar Foto">


<s:VGroup width="320" height="320" gap="10">
<mx:UIComponent id="uic" width="100%"
height="100%"/>
<s:Button label="OK" width="100%">
<s:click>
<![CDATA[
var foto:BitmapData = new
BitmapData(300,300);
foto.draw(videoCam);
img.source = new
Bitmap(foto);
cb.closeDropDown();
]]>
</s:click>
</s:Button>
</s:VGroup>
</s:CalloutButton>
</s:HGroup>

<s:Image width="200" height="200" id="img"/>

</s:View>

Neste exemplo, adicionamos a saída da câmera em um Callout Button, e depois criamos um


botão que tira a “foto” da câmera. Lembre-se que deve estar habilitado o acesso da câmera
pela aplicação

.
10.8 Tirar uma foto nativamente
Também é possível usar a aplicação nativa do dispositivo para tirar uma foto. Para isso,
usamos a classe CameraUI e o evento MediaEvent.COMPLETE, que é disparado após o
usuário tirar a foto.

/MobileAPI/src/views/TirarFoto.mxml
<?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="TirarFoto">

<s:layout>
<s:VerticalLayout paddingBottom="10" paddingLeft="10"
paddingRight="10" paddingTop="10"/>
</s:layout>

<s:Button label="Tirar Foto">


<s:click>
var camera:CameraUI = new CameraUI();
camera.addEventListener(MediaEvent.COMPLETE,
function(event:MediaEvent):void {
imagem.source = event.data.file.url;
});
camera.launch(MediaType.IMAGE);
</s:click>
</s:Button>

<s:Image id="imagem" width="100%" height="100%"/>

</s:View>

10.9 Acelerômetro
A maioria dos dispositivos mobile possuem hoje o recurso de acelerômetro, que é
responsável em capturar a rotação do dispositivo, descobrindo se o mesmo está em pé ou
deitado.

Para descobrir se um dispositivo possui este recurso, use o método isSupported da


classe Accelerometer. Para obter informação dos eixos X, Y, Z, analise o evento
UPDATE, de acordo com o exemplo a seguir:
/MobileAPI/src/views/Acelerometro.mxml
<?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="Acelerometro">

<s:layout>
<s:VerticalLayout paddingBottom="10" paddingLeft="10"
paddingRight="10" paddingTop="10"/>
</s:layout>

<fx:Script>
<![CDATA[
import flash.sensors.Accelerometer;
]]>
</fx:Script>

<s:creationComplete>
<![CDATA[

if (Accelerometer.isSupported)
{
var a:Accelerometer = new Accelerometer();

a.addEventListener(AccelerometerEvent.UPDATE,function(event:Ac
celerometerEvent):void {

eixoX.text = "Eixo x: " + event.accelerationX;


eixoY.text = "Eixo y: " + event.accelerationY;
eixoZ.text = "Eixo z: " + event.accelerationZ;

});
}

]]>
</s:creationComplete>

<s:Label id="eixoX"/><s:Label id="eixoY"/><s:Label


id="eixoZ"/>

</s:View>
10.10 GPS
Dispositivos que possuem acesso a GPS também podem fornecer informações para o Flex
Mobile, bastando apenas usar a classe GeoLocation.

/MobileAPI/src/views/NavegadorGPS.mxml
<?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="GPS">

<s:layout>
<s:VerticalLayout paddingBottom="10" paddingLeft="10"
paddingRight="10" paddingTop="10"/>
</s:layout>

<fx:Script>
<![CDATA[
import flash.sensors.Geolocation;
]]>
</fx:Script>

<s:creationComplete>
<![CDATA[

if (Geolocation.isSupported)
{
var g:Geolocation = new Geolocation();

g.addEventListener(GeolocationEvent.UPDATE,function(event:Geol
ocationEvent):void {

latitude.text = "Latitude: " + event.latitude;


longitude.text = "Longitue: " + event.longitude;

});
}

]]>
</s:creationComplete>

<s:Label id="latitude"/>
<s:Label id="longitude"/>

</s:View>
Tanto a classe GeoLocation quanto Accelerometer possuem o mesmo esquema, disparando
o evento UpDate e capturando informações pelo evento. Se a informação não aparecer,
verifique se a aplicação está com permissão de acesso ao GPS.

Você também pode gostar