Adobe Flex Mobile
Transcrição
Adobe Flex Mobile
Dominando Adobe Flex Mobile Parte 1 Daniel Pace Schmitz www.danielschmitz.com.br www.flex.etc.br Esta obra digital é parte integrante do livro Dominando Flex Mobile, fornecida de forma gratuita para os leitores. Uma correção ortográfica mais rígida ainda não foi realizada, e caso encontre algum erro, por favor informe para [email protected] 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. Nesta primeira parte da obra, mostramos o básico do Adobe Flash Builder 4.5, exibindo todos os conceitos necessários para criar uma aplicação simples para o seu dispositivo mobile. Na segunda parte da obra, que ainda será lançada, iremos discutir todos os conceitos avançados incluindo suporte aos dispositivos Android e iOs, além de criar uma aplicação completa para restaurantes. Aguardem! Interessado na segunda parte da obra ? Nós criamos uma newsletter para que você possa receber email com novidades e promoções sobre os nossos livros. Você pode cadastrar o seu email no link a seguir: Clique aqui para preencher a nossa newsletter 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: Site: Email para suporte: Twitter: Daniel Pace Schmitz www.danielschmitz.com.br [email protected] @Daniel_Schmitz SUMÁRIO 1 2 3 Introdução ....................................................................................................................... 1 1.1 O que é o framework Flex? .................................................................................... 1 1.2 O que é MXML? ...................................................................................................... 2 1.3 O que é Action Script? ............................................................................................ 3 1.4 Como o Flex Mobile funciona? ............................................................................... 3 1.5 Instalação do Adobe Flash Builder 4.5 ................................................................... 4 1.6 Como esta obra está dividida ................................................................................. 5 Conhecendo o Flex Mobile .............................................................................................. 6 2.1.1 Perspective ......................................................................................................... 7 2.1.2 Workspace ......................................................................................................... 7 2.1.3 Editor.................................................................................................................. 7 2.1.4 Project ................................................................................................................ 8 2.2 Tipos de projetos no Flash Builder 4.5 ................................................................... 8 2.3 Criando o primeiro projeto Flex Mobile ............................................................... 10 2.4 Configurando e executando o projeto Mobile ..................................................... 13 2.5 Executando através de um outro dispositivo ....................................................... 14 2.6 Entendendo a arquitetura do Flex Mobile ........................................................... 16 2.7 Views .................................................................................................................... 17 2.8 Componentes recomendados .............................................................................. 18 2.9 Mais considerações para o framework Mobile .................................................... 18 Design e workflow do componente View ...................................................................... 20 3.1 Criando uma nova view ........................................................................................ 21 3.2 Navegando entre views ........................................................................................ 23 4 3.3 Parâmetros do pushView e popView ................................................................... 28 3.4 Outros métodos para navegação entre Views ..................................................... 28 3.5 Action Bar ............................................................................................................. 29 3.6 Escondendo a Action Bar...................................................................................... 31 3.7 Utilizando ícones .................................................................................................. 32 3.8 Definindo menus para as views ............................................................................ 32 3.9 Criando uma aplicação mobile com TabBars (Sections) ....................................... 36 3.10 Configurando a disposição do dispositivo mobile (Retrato ou paisagem) ........... 38 3.11 Persistência de dados na View ............................................................................. 39 Componentes do Flex Mobile Framework ..................................................................... 41 4.1 ActionBar .............................................................................................................. 41 4.2 BusyIndicator ........................................................................................................ 41 4.3 TabbedViewNavigatorApplication........................................................................ 42 4.4 ViewNavigatorApplication .................................................................................... 44 4.5 View ...................................................................................................................... 44 4.6 ViewMenu ............................................................................................................ 45 4.7 Button................................................................................................................... 45 4.8 CheckBox .............................................................................................................. 46 4.9 Group.................................................................................................................... 47 4.10 Image .................................................................................................................... 47 4.11 Label ..................................................................................................................... 49 4.12 List ........................................................................................................................ 49 4.13 RadioButton ......................................................................................................... 49 4.14 RadioButtonGroup ............................................................................................... 50 4.15 TextInput .............................................................................................................. 50 5 6 Trabalhando com listas .................................................................................................. 52 5.1 O evento change .................................................................................................. 52 5.2 Item Renderers no List ......................................................................................... 54 5.3 Conhecendo o IconItemRenderer ........................................................................ 55 Criando a aplicação FlexTasks ........................................................................................ 59 6.1 Criando o projeto ................................................................................................. 59 6.2 Incluindo ícones.................................................................................................... 62 6.3 Persistência de dados ........................................................................................... 63 1 Introdução Em 2011 o framework Adobe Flex 4.5 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. Com novas versões do framework, lançadas ao longo dos anos, chegamos na atual versão em maio de 2011 (Flex 4.5), e possivelmente em junho/julho de 2011 teremos a versão 4.5.1. Nestas atuais versões, 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., meio que “na mão”, ficará a vontade com MXML. Se você nunca usou HTML (você é dev?), 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. Ok, estamos falando muito de Action Script, ele merece um novo tópico. 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, 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 nativamente no sistema operacional. 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 . 1.5 Instalação do Adobe Flash Builder 4.5 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.5, que instala tudo que precisamos deixando o Flex pronto para ser utilizado. 2 Para realizar o download do Flash Builder 4.5 acesse este link e, ao lado direito do site, localize o item “Flash Builder 4.5 Premium” e clique em “try”. 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. Após o download terminar, execute o arquivo de instalação e aguarde a 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 1 http://www.adobe.com/flashplatform/certified_devices/ 2 http://www.adobe.com/products/flash-builder.html 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 abertos. Aguarde a conclusão da instalação. O Flash Builder 4.5 não é gratuito, ele é pago, mas existem versões de avaliação por 60 dias, 3 e versões para estudantes e desempregados . Você pode usar o Flash Builder 4.5 para aprender Flex, e decidir pela compra da IDE somente quando estiver confortável quanto ao seu uso. O framework Flex SDK 4.5 é 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.5 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 desta obra envolve a criação de uma aplicação destinada a realização de pedidos de um restaurante, envolvendo todos os conceitos aprendidos. 3 https://freeriatools.adobe.com/ 2 Conhecendo o Flex Mobile Após a instalação do Flash Builder 4.5, 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.5 O termo workbench é usado para ilustrar todos os recursos de visualização do Flash Builder 4.5 relativos a suas configurações e janelas. Como o Flash Builder 4.5 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.5 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.5. 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.5. Apesar de pouco usado, este conceito pode ser útil em determinadas situações relacionadas a 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.5. 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.5 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.5 Existem duas formas para criar um projeto Flex no Flash Builder 4.5. 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 Mobile 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 Nesta obra estaremos utilizando quase todos os projetos envolvidos, principalmente quando formos criar a aplicação final. 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 Como 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 inicial da aplicação, neste caso o Google Android. Outras plataformas (iphone, ipad e outras) serão adicionadas na versão 4.5.1. Nota do autor: Talvez você já tenha acesso a versão para iOs (iphone/ipad), mas isso não foi possível enquanto escrevíamos o livro. Nota do autor 2: Veja que, mesmo não podendo estabelecer a versão para iPhone neste momento, não significa que você não poderá criar uma aplicação para iPhone. Após escolher a plataforma Google Android, 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. Estas configurações serão abordadas com mais detalhes na segunda parte desta obra. 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. Este conceito é discutido no próximo capítulo. 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”, não faz sentido... 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 aplica 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 Spark BusyIndicator Spark TabbedViewNavigator Application Spark TabbedViewNavigator Spark View Spark ViewMenu Spark ViewNavigator Spark ViewNavigatorApplication Spark Button Spark CheckBox Spark DataGroup Spark Group Spark HGroup / VGroup Spark TileGroup Spark Image / BitmapImage Spark Label Spark List Spark RadioButton Spark RadioButtonGroup Spark SkinnableContainer Spark Scroller Spark TextArea Spark TextInput 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. 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 novos 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 HelloWorldHomeView.mxml. foram criados: HelloWorld.mxml e /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 ViewNavigatorApplication. 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 é aprimeira 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, lembra??) que aprendemos na faculdade. Neste momento, você deve lembrar daqueles comandos push e pop de um array, 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[ this.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 arual 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 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: popToFistView: 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: 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.6 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.7 Utilizando ícones Na 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.8 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.9 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 Home Tab2 Config Tab3 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.10 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.11 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 (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. 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, e será amplamente utilizada em nossos exemplos. 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). Dica: Nos componentes a seguir, mostramos no lado direito, logo abaixo do título, o caminho completo de cada componente. Se você quer saber mais sobre o componente em questão, experimente copiar/colar este caminho no Google. 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 da View. 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.5, 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.8. 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. Graças 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="{mx.controls.Alert.show('Hello Wolrd')}"/> OU <fx:Script> <![CDATA[ import mx.controls.Alert; protected function OnButtonClick (event:MouseEvent):void { mx.controls.Alert.show(‘Hello World’); } ]]> </fx:Script> <s:Button id="btn2" label="Button" click="OnButtonClick (event)"/> Ou <s:Button id="btn3" label="Button"> <s:click> <![CDATA[ mx.controls.Alert.show('Hello World'); ]]> </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 exibir uma mensagem de alerta. 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.5 é 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 normalmente 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 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. 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 mx: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. É 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. Outra dica é incorporar imagens somente que são reutilizadas. Por exemplo, um ícone que será exibido somente em um Panel que quase nunca é acessado, mesmo que contenha 5KB, não deve estar incorporado. Imagine 10 panels desta forma, você já economizou 50K no tamanho inicial do arquivo SWF. Uma novidade da versão 4.5 é 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. 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. Isso é feito no botão criado logo após os três Radios. 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. 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%" <s:dataProvider> <s:ArrayList> <fx:Object <fx:Object <fx:Object </s:ArrayList> </s:dataProvider> labelField="firstName"> firstName="Daniel" /> firstName="Fulano" /> firstName="Beltrano" /> <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 Use somente LabelItemRenderer e IconItemRenderer. 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 controlas nossas pequenas tarefas do dia a dia. Esta aplicação possui o código fonte para download. No código fonte, eu comentei cada método e cada funcionalidade para facilitar o entendimento. Estes comentários não são exibidos nos códigos a seguir para que não poluam o código da obra, que deve ser o mais enxuto possível. É importante lembrar que ainda não estamos preparados para o desenvolvimento mobile, pois o mesmo exige conhecimento específico do dispositivo e de toda a sua API (acessar dados do telefone, GPS, acelerômetro, etc), mas isso será visto nos próximos capítulos, na segunda parte desta obra. 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.5 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. Neste caso, Google Android. 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). Sinceramente eu não gosto da 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 de implementações do próprio framework mobile. Como foi visto no capítulo 3.11, 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 classe bastante pequena, nativa do Flex 4.5, que possui uma implementação do recurso de SharedObject, que já deve ser conhecido pelos usuários do 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: /FlexTasks/src/vos/Task.as package vos { [Bindable] public class Task { public var public var public var public var name:String; description:String; priority:uint=1; 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, fazendo o link dos dados do formulário ao objeto diretamente. 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 = "INTASKS_COMPLETAS"; //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 presenta 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.topLevelApplication 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. Com a aplicação de tarefas funcionando, chegamos ao final da primeira parte desta obra, onde aprendemos o básico de uma aplicação Flex Mobile. Aguardem pela segunda parte da obra, que deverá ocorrer daqui há alguns meses.