mobile 067 asqgbnyu

46

Upload: ramon-souza

Post on 12-Jan-2016

43 views

Category:

Documents


1 download

DESCRIPTION

Veja todos os artigos disponíveis na edição 67 da Revista Mobile Magazine. Edição que tem como destaque o iOS 8 e Swift: fique por dentro das novidades da Apple.

TRANSCRIPT

Page 1: Mobile 067 Asqgbnyu
Page 2: Mobile 067 Asqgbnyu
Page 3: Mobile 067 Asqgbnyu

Sumário

A Mobile Magazine tem que ser feita ao seu gosto. Para isso, precisamos saber o que você, leitor, acha da revista!

Dê seu voto sobre este artigo, através do link:

devmedia.com.br/webmobile/feedback

seu Feedback

sob

re esta edição

Dê seu feedback sobre esta edição!Artigo no estilo Curso

20 – Introdução ao Framework ORM Android JPDroid – Parte 2[ Rafael Centenaro e RobisonCrisBrito ]

Conteúdo sobre Boas Práticas

11 – Desenvolvimento em Switf com Xcode [ Madson Aguiar Rodrigues ]

Conteúdo sobre Boas Práticas, Conteúdo sobre Novidades

04 – Conheça as novidades do iOS 8[ Alexandre Oliveira ]

Artigo sobre Novidades, Artigo no estilo Solução Completa

34 – Jogos em Cordova: Desenvolvendo um jogo 2D com Enchant.js – Parte 2[ Julio Sampaio ]

67ª Edição - 2015 ISSN 1807736-6

Editor

Rodrigo Oliveira Spínola ([email protected])

Subeditor

Eduardo Oliveira Spínola

Consultora Técnica

Daniella Costa ([email protected])

ProduçãoJornalista Responsável Kaline Dolabella - JP24185

Capa e Diagramação Romulo Araujo

Fale com o Editor!

É muito importante para a equipe saber o que você está achando da revista: que tipo de artigo você gostaria de ler, que artigo você mais gostou e qual artigo você menos gostou. Fique a vontade para entrar em contato com os editores e dar a sua sugestão!Caso tenha interesse em publicar um artigo na revista ou no site Mobile Magazine, entre em contato com os editores, informando o título e mini-resumo do tema que você gostaria de publicar:

Rodrigo Oliveira Spínola - Editor da [email protected]

RoDRigo olivEiRa SPínola

Editor Chefe da SQL Magazine, Mobile

e Engenharia de Software Magazine.

Professor da Faculdade Ruy Barbosa,

uma instituição parte do Grupo DeVry.

Doutor e Mestre em Engenharia de

Software pela COPPE/UFRJ.

Assine agora e tenha acesso a todo o conteúdo da DevMedia:www.devmedia.com.br/mvp

atendimento ao leitorA DevMedia possui uma Central de Atendimento on-line, onde você pode tirar suas dúvidas sobre serviços, enviar críticas e sugestões e falar com um de nossos atendentes. Através da nossa central também é possível alterar dados cadastrais, consultar o status de assinaturas e conferir a data de envio de suas revistas. Acesse www.devmedia.com.br/central, ou se preferir entre em contato conosco através do telefone 21 3382-5038.

[email protected] – 21 3382-5038

anúncios – Anunciando nas publicações e nos sites do Grupo DevMedia, você divulga sua marca ou produto para mais de 100 mil desenvolvedores de todo o Brasil, em mais de 200 cidades. Solicite nossos Media Kits, com detalhes sobre preços e formatos de anúncios.

EXPEDiEnTE

Page 4: Mobile 067 Asqgbnyu

4 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 5 4 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 5

Este apresenta as principais novidades do iOS 8 e como elas estão

estruturadas. Serão apresentadas as seguintes novidades: Adaptive

Layout (que permite o desenvolvimento de aplicações que se adaptam

melhor a diferentes tipos de tela), extensões (que permitem que seu

aplicativo interaja diretamente com o sistema operacional), CloudKit

(que permite manipular informações na nuvem), scene kit (que facilita

o desenvolvimento de jogos 3D), handoff (que permite que o usuário

continue seu trabalho de onde parou em qualquer dispositivo) e o live

rendering (que permite a visualização de componentes desenvolvidos

em tempo de projeto). A discussão deste tema é útil no sentido de

conhecermos as novas possibilidades de desenvolvimento e como

podemos fazer uso delas para aprimorar nossos aplicativos.

Fique por dentro

Conheça as novidades do iOS 8Lançado em setembro de 2014 e considerada a

maior atualização até o momento, com mais de quatro mil novas APIs, o iOS 8 trouxe para

os desenvolvedores uma série de facilidades que ex-pandem as possibilidades para o desenvolvimento de suas aplicações, além de permitir que elas interajam diretamente com o sistema operacional (o que antes não era possível uma vez que a aplicação ficava totalmente encapsulada).

Diferente do que ocorre todo ano, a nova versão do sistema operacional não se limitou a novas funcionalida-des, trazendo junto uma nova linguagem multiparadig-ma chamada Swift, além do lançamento do WatchKit, o framework para desenvolvimento com Apple Watch.

Uma linguagem de programação multiparadigma su-porta mais de uma forma de se programar, o que permite ao desenvolvedor escolher como seu código pode ser representado e lido. O Swift suporta os paradigmas:• funcional: onde a função é o objeto mais importante de uma execução;• orientado a objetos: onde as informações são mape-adas de acordo com o mundo real em classes;• imperativo: onde sequências de comandos são neces-sárias para se obter o resultado de uma execução, e;• estruturada em blocos: onde o código é organizado em blocos de execução.

Neste artigo falaremos da nova forma de criar inter-faces conhecida como Adaptive Layout, que nos permite criar uma única interface para todos os dispositivos; extensões, que nos permitem criar widgets na tela de no-tificações; CloudKit, um armazenamento em nuvem gra-tuito; scene kit, que nos permite criar de forma simples jogos 3D; entre outras novidades como o handoff, para dar continuidade do trabalho em qualquer dispositivo, o live rendering, que facilita a criação de componentes visuais, acabando com a limitação de não ser possível mostra-los no Interface Builder, e o novo framework para trabalhar com fotos e criar efeitos profissionais, o PhotoKit.

adaptive layoutJá foi a época em que nossas interfaces criadas no

Interface Builder representavam um espelho do que iria ser mostrado quando executadas nos aparelhos. Após

o lançamento do iPad, nossa única preocupação era desenhar interfaces distintas que aproveitavam toda sua área útil. Depois surgiram as resoluções do tipo retina, que utilizavam a mesma área útil com uma maior densidade, bastando a criação de imagens com o dobro de resolução nos famosos arquivos @2x. Em seguida a Apple lançou o iPhone 5 com quatro polegadas e consequente-mente, para evitar duplicidade e tentar facilitar a vida dos desen-volvedores, substituiu o Spring and Struts, utilizado para ajustar a interface de acordo com a rotação das telas pelo Auto Layout, que nos permitia uma maior controle em diferentes resoluções.

Não é nenhuma novidade a complexidade que o Auto Layout introduziu no desenvolvimento de aplicativo, porém a sua natu-reza limitada e o lançamento de outros modelos de dispositivos já indicavam sua vida curta.

Para evitar que os desenvolvedores continuassem a se preocu-par em qual dispositivo seu aplicativo estaria sendo executado e como ele deveria se comportar esteticamente (como podemos ver na Listagem 1 onde são definidos vários macros para serem utilizados na detecção do dispositivo), a Apple introduziu o Adaptive Layout.

Como sabemos, criar interfaces para tamanhos distintos não é um trabalho prazeroso ou produtivo. O Adaptive Layout facilita este trabalho que um layout se adapte a qualquer dispositivo e tamanho. Uma forma simples de explicar o Adaptive Layout é que ele permite que nós desenvolvedores criemos nossas interfaces em uma única tela e esta irá se adaptar a qualquer dispositivo, sem distinção de tamanho ou orientação, inclusive aqueles que sequer foram lançados.

Page 5: Mobile 067 Asqgbnyu

4 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 5 4 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 5

O Adaptive Layout não é apenas uma tecnologia, mas sim um conjunto de paradigmas que nos permitem pensar de uma forma universal como mostrado na Figura 1.

As seguintes tecnologias são utilizadas no Adaptive Layout:• Universal Storyboard: storyboard é uma tecnologia inserida na versão 5 do iOS que nos permite criar interfaces e navegação de uma maneira visual, diminuindo em muitas linhas de código nossos aplicativos e separando a lógica de criação de interfaces da lógica de negócio. Antes do iOS 8, uma prática comum era criar storyboards diferentes para iPhone e iPad. O Universal Storybo-ard centraliza toda a navegação do sistema em um único ponto, facilitando o entendimento e manutenção, além de permitindo que em alguns casos, direcionemos o fluxo de telas para um view controller diferente;• Transition Coordinates: introduzido na versão 7 do iOS, são protocolos como o UIViewControllerTransitionCoordinator, utilizados para executar animações e adaptar a interface perante mudanças de telas ou orientação, o que antes fazíamos dentro de métodos como viewWillAppear;• Adaptive View Controller Hierarchies: utilizado para permitir hierarquias diferentes em dispositivos diferentes. Você já deve conhecer esta técnica utilizada no iPad quando utilizamos o UISplitViewController (que agora também funciona no iPhone). Na vertical, ele se mostra como um navigation controller e na ho-rizontal como duas views distintas. A diferença é que agora você pode ter este mesmo comportamento em suas telas. Na Figura 2 podemos ver um exemplo desta transição;• Presentation Controllers: permite definir nossos próprios view controllers para serem utilizados em animações e transições.

Na prática, com o uso do Adaptive Layout, podemos criar inter-faces para diversos dispositivos de uma única vez, customizando interações de telas de acordo com nossas necessidades e diminuin-do ainda mais o acoplamento entre interface e negócio.

app ExtensionsO App extension é uma das boas novidades do iOS 8, permitindo

que seu aplicativo se expanda para além de sua sandbox, interagin-do com o próprio sistema operacional. A palavra sandbox significa que o aplicativo está confinado a uma área restrita, onde suas ações são coordenadas pelo sistema operacional e seus usuários.

Figura 1. As diferentes interfaces suportadas pelo Adaptive Layout

Listagem 1. Macros para detectar em qual dispositivo o código está sendo executado.

#define IS_IPAD (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) #define IS_IPHONE (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) #define IS_RETINA ([[UIScreen mainScreen] scale] >= 2.0) #define SCREEN_WIDTH ([[UIScreen mainScreen] bounds].size.width) #define SCREEN_HEIGHT ([[UIScreen mainScreen] bounds].size.height) #define SCREEN_MAX_LENGTH (MAX(SCREEN_WIDTH, SCREEN_HEIGHT)) #define SCREEN_MIN_LENGTH (MIN(SCREEN_WIDTH, SCREEN_HEIGHT)) #define IS_IPHONE_4_OR_LESS (IS_IPHONE && SCREEN_MAX_LENGTH < 568.0) #define IS_IPHONE_5 (IS_IPHONE && SCREEN_MAX_LENGTH == 568.0) #define IS_IPHONE_6 (IS_IPHONE && SCREEN_MAX_LENGTH == 667.0) #define IS_IPHONE_6P (IS_IPHONE && SCREEN_MAX_LENGTH == 736.0)

Figura 2. UISplitViewController em diferentes orientações

Todo aplicativo executado dentro do sistema operacional iOS está confinado em um espaço de memória único, possuindo sua área própria para gravação em disco e variáveis de ambiente, como o User Defaults. Toda interação do aplicativo com o sistema operacional e outros aplicativos é efetuado através de APIs que garantem a segurança do sistema operacional e do usuário.

Como tudo que a Apple faz é voltado primeiramente aos usuários e sua segurança, as extensões estão limitadas até o momento a alguns templates fornecidos:• Today: conhecidos como widgets, são mostrados na tela de notificações. Ainda existe muita controvérsia do que se pode ou não mostrar como widget, mas a ideia principal é atualizar o usuário com informações rápidas sem a necessidade de entrar no aplicativo, como ocorre com o aplicativo de calendário e clima;• Share: permite que seu aplicativo compartilhe informações diretamente para mídias sociais ou outros serviços online como o

Page 6: Mobile 067 Asqgbnyu

Conheça as novidades do iOS 8

6 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 7 6 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 7

Dropbox. Se o seu aplicativo permite salvar dados em um servidor remoto, você poderá utilizar esta extensão para permitir que o usuário salve as informações diretamente de outro aplicativo;• Action: permite que o usuário execute “ações” predefinidas pelo seu aplicativo como salvar um link através do Safari e até mesmo editar documentos abertos;• Photo Editing: permite que o usuário, a partir do aplicativo Fotos ou diretamente da câmera, chame seu aplicativo para apli-car algum filtro ou editar a mesma. Até o momento a edição de vídeos não é suportada;• Document Provider: se o seu aplicativo possui uma funciona-lidade de backup, em nuvem, você poderá permitir que o usuário faça upload e download de qualquer aplicativo para seu serviço. Outra possibilidade é permitir que seu aplicativo disponibilize uma pasta onde outros aplicativos poderão obter e salvar arquivos. Esta pasta também ficará disponível para qualquer aplicativo que utilize o document picker para selecionar documentos existentes;• Custom Keyboard: permite criar teclados customizados para serem utilizados em todo sistema.

A seleção de extensões é possível após criarmos um novo Target em nossa aplicação, como mostrado na Figura 3.

As extensões, mesmo que limitadas, nos permitem pensar além de nosso aplicativo e melhorar a experiência dos usuários.

CloudKit Quem trabalha com desenvolvimento de sistemas, em algum momento precisou ou irá precisar acessar serviços para gravar e recuperar informações de um servidor remoto. A criação destes serviços demanda um enorme trabalho e muitas vezes, em equipes pequenas ou quando estamos desenvolvendo sozinhos, atuar nas duas pontas se torna uma tarefa inviável.

Figura 3. Seleção de template para criação de extensões

A ideia do CloudKit é livrar o desenvolvedor do trabalho de criar serviços e manter toda uma infraestrutura como banco de dados, webservices e lógica de validação. Para quem já trabalhou com seu antecessor, o iCloud, sofreu com sua péssima implementação e instabilidade. Quando utilizamos o CloudKit, as informações ficam divididas em duas categorias: informações da aplicação, que são consideradas dados públicos ao aplicativo e; informações do usuário, o qual são isoladas e não permitem o acesso por parte dos desenvolvedores.

A seguir elencamos algumas vantagens e desvantagens ao se utilizar o CloudKit para armazenar informações em nuvem:• Vantagens:

- Custo zero;- Autenticação transparente pelas credenciais do iCloud: possi-bilita que o usuário autenticado pelo iCloud não necessite inse-rir novamente sua senha para sincronizar suas informações;- Não necessita de bibliotecas externas;- Fácil implementação.

• Desvantagens:- Não funciona em outras plataformas como Windows Phone e Android;- As informações do usuário ficam em uma caixa preta, o que não permite depurar qualquer tipo de inconsistência das informações;- O armazenamento off-line das informações fica a cargo do desenvolvedor.

A Apple tentou criar algo confiável para seus desenvolvedores utilizarem seguindo os moldes de BaaS, porém existem diversas plataformas no mercado como o FireBase e Parse que fazem o mes-mo trabalho, de uma maneira mais confiável e multiplataforma, além de funcionarem de forma transparente quando o usuário

está off-line. BaaS, o acrônimo de Backend as a Service, são serviços que livram o desenvolvedor da tarefa de criar e manter uma in-fraestrutura local de servidores. Os serviços deste tipo permitem a criação de servidores virtuais e a instalação de ferramentas como banco de dados e frameworks. A administração destes servi-dores virtuais fica a critério do desenvolvedor, porém possuem a vantagem de serem escaláveis e não demandarem espaço físico. O serviço da Amazon chamado S2 é um exemplo conhecido da utilização de BaaS.

Outras opções também confiáveis são servidores nos mol-des de PaaS, acrônimo de Platform as a Service, PaaS são plataformas

Page 7: Mobile 067 Asqgbnyu

6 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 7 6 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 7

completas onde o desenvolvedor só precisa se preocupar em subir e executar seu código, disponibilizando serviços de banco de dados e escalabilidade sem a necessidade de administração dos recursos. O Google Cloud é um serviço conhecido que funciona nos moldes do PaaS, permitindo que os desenvolvedores executem código em PHP, Java e Go, além de prover banco de dados relacio-nal e orientado a objeto de uma maneira transparente.

Scene KitPor muitos anos, a criação de jogos 2D foi dominada pelo framework

cocod2D, assim como a Unity 3D vinha se mantendo líder no mer-cado 3D. Neste período, a Apple se viu pressionada a padronizar o mundo 2D, criando seu próprio framework chamado Sprite Kit no lançamento do iOS 7. Entretanto, o mundo 3D ainda se mantinha sem uma solução nativa e de fácil utilização, pois a curva de aprendizado de frameworks como Unity e OpenGL nunca foi das melhores.

Disponível desde 2012 para plataforma Mac OSX, o Scene Kit foi portado para iOS nesta versão 8, permitindo que os desenvolve-dores desta plataforma usufruíssem das mesmas vantagens no desenvolvimento de jogos 3D.

Mas como funciona o Scene Kit? Basicamente como uma árvore hierárquica de nós que é chamada de scene graph, com cada scene possuindo um nó principal, chamado de root node. Este representa as coordenadas de nosso mundo 3D e cada objeto neste mundo é representado por um ou mais nodes que se ligam, como uma imensa teia de aranha. Esta grande teia de aranha, quando executada, é processada diretamente na GPU (Graphics Processing Unit), a placa de vídeo dos smartphones e tablets.

Quem nunca trabalhou com OpenGL acaba se sentindo intimida-do, pois é uma tecnologia pouco amigável para quem não tem uma boa base matemática devido à criação de jogos necessariamente exigir um conhecimento prévio sobre coordenadas e gráficos, como representado na Figura 4.

O Scene Kit é formado por vários componentes, como mostra-remos a seguir:• SCNView: representa a view dentro do Scene Kit. Podemos fazer uma analogia ao UIView, que utilizamos diariamente no desenvolvimento de aplicações;• SCNScene: representa uma scene, que é um conjunto de nós contendo informações sobre a cena a ser mostrada como luzes, câmeras e coordenadas;• SCNNode: uma cena é formada de vários nós, e cada nó pode conter informações sobre posição da câmera, intensidade da ilu-minação, coordenadas na tela, entre outras diversas informações. Esta classe representa cada um destes nós;• SCNGeometry: uma geometria é um objeto que representa uma coordenada no mundo 3D. Com esta classe é possível modelarmos nossos objetos e os adicionarmos aos nós;• SCNMaterial: representa as informações sobre textura e cor de objetos, e como estes se comportam de acordo com a iluminação;• SCNLight: representa a iluminação e sombreamento de um objeto;

Figura 4. Sistema de coordenadas do SceneKit

Figura 5. Scene Kit em ação

• SCNCamera: representa a posição da câmera de um objeto;• SCNSceneRenderer: responsável pela renderização das views, é um protocolo que provê os métodos necessários para renderi-zação das telas.

Com os conceitos definidos, fica bem mais fácil entender o fun-cionamento do SceneKit. Esta nova API traz uma facilidade para criação de jogos 3D, que junto de seu irmão Sprite Kit, permitirá um maior nível de controle e produtividade no desenvolvimento de jogos, além de poder ser utilizado também em aplicações (veja um exemplo na Figura 5).

Page 8: Mobile 067 Asqgbnyu

Conheça as novidades do iOS 8

8 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 9 8 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 9

PhotoKitO aplicativo Fotos, que acompanha o sistema operacional iOS, foi

desenvolvido inteiramente com o framework PhotoKit. Para muitos pode parecer algo simples, mas quantos de nós já nos deparamos com aquele efeito ou funcionalidade própria dos aplicativos da Apple e tivemos que buscar bibliotecas de terceiros ou perder um vasto tempo desenvolvendo a mesma, quando a Apple poderia simplesmente ter disponibilizado em sua API?

Agora também temos a possibilidade de ser informado quando uma foto do álbum foi modificada. O PhotoKit veio para substituir o framework AssetLibrary utilizado para carregar fotos e vídeos do álbum de fotos, possuindo a seguinte estrutura:• PHObject: uma classe abstrata de onde outros objetos herdam, contendo uma única informação que identifica o objeto chamada de localIdentifier;• PHAsset: representa uma imagem ou vídeo que aparece no aplica-tivo Fotos, além de informações próprias como extensão, visibilidade, data de criação, se foi marcado como favorito, entre outros;• PHAssetCollection: grupos de assets, que representam uma foto ou vídeo, são chamados de PHAssetCollection. Esta coleção pode representar um álbum ou “momento” dentro da biblioteca de fotos e vídeos, além dos chamados “smart albums”, que incluem vídeos, itens recentes, favoritos e muito mais;• PHCollectionList: são listas de objetos de PHAssetCollection, possuindo um nível hierárquico como aparece no aplicativo Fo-tos como ano, nome do evento ou grupos de fotos criados pelo usuário;• PHFetchOptions: representa as opções que serão utilizadas para se buscar o asset, podendo ser utilizado para aplicar filtros na busca; • PHFetchResult: representa um resultset com o resultado da busca;• PHImageManager: quando fazemos buscas com o framework PhotoKit, o resultado contém apenas metadados dos objetos. Para carregar o objeto real, precisamos utilizar esta classe que possui a facilidade de trabalhar de forma assíncrona e disponibilizar cache e redimensionamento dos objetos;• PHCachingImageManager: gerencia o cache das imagens ou vídeos.

Para aqueles acostumados com o framework do Core Data, o PhotoKit possui uma API bem parecida. Na Listagem 2 podemos verificar um exemplo do uso do framework PhotoKit para listar imagens marcadas como favoritas pelo usuário.

live RenderingNormalmente, quando criamos nossos próprios componentes

visuais e os utilizamos dentro do Interface Builder, perdemos a funcionalidade de preview deste componente e a cada modifica-ção, precisamos rodar o aplicativo para visualizar tais alterações. O Live Rendering veio para corrigir esta falha.

Para que isto ocorra, precisamos anotar a classe responsável pela criação do componente com o atributo @IBDesignable, como mostrado na Listagem 3.

Listagem 2. Exemplo de uso do framework Photo Kit.

func loadImages() { // array para armazenar as imagens var assets: [UIImage] = [] // opções da busca let options = PHFetchOptions() // responsável pelo carregamento das imagens let manager = PHImageManager.defaultManager() // apenas marcadas como favoritas em ordem crescente // pela data de criação options.predicate = NSPredicate( format: “favorite == YES”) options.sortDescriptors = [NSSortDescriptor( key: “creationDate”, ascending: true)] // carrega o metadados das imagens let result = PHAsset.fetchAssetsWithMediaType( PHAssetMediaType.Image, options: options) // obtém o UIImage para cada PHAsset retornado result.enumerateObjectsUsingBlock { (object, idx, _) in if let asset = object as? PHAsset { manager.requestImageForAsset( asset, targetSize: PHImageManagerMaximumSize, contentMode: .AspectFill, options: nil, resultHandler: { (image, info) in // image contém o UIImage // info contém o metadados da imagem assets.append(image) }) } } }

Listagem 3. Classes anotada com o atributo @IBDesignable.

import Foundationimport UIKit

@IBDesignableclass CustomView: UIView { }

Ao utilizarmos esta classe dentro do Interface Builder, ao ve-rificarmos no identity inspector da mesma, veremos uma nova propriedade chamada Designables, com seu status, como podemos verificar na Figura 6.

São dois os possíveis status para este atributo:• Up to date: o componente foi compilado e renderizado e já pode ser visto de dentro da interface builder;• Build failed: indica que ocorreu um erro ao tentar renderizar o componente.

Page 9: Mobile 067 Asqgbnyu

8 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 9 8 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 9

Além da classe, podemos utilizar o atributo @IBInspectable para anotar nossas variáveis, como pode ser visto no código a seguir, permitindo que as mesmas sejam mostradas no atribute inspector do componente, como mostrado na Figura 7:

@IBInspectable var color : UIColor = UIColor.blackColor()

Listagem 5. As possíveis interações com o handoff.

import UIKit

class HandoffExample: UIViewController { override func viewDidLoad() { super.viewDidLoad() startActivity() } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } // inicia uma activity func startActivity() { let activity = NSUserActivity( activityType: “br.com.soli.example.handoff”) activity.title = “Exemplo Activity” activity.userInfo = [“example.data”: [“Handoff”, “iOS8”]] self.userActivity = activity } // atualiza a activity override func updateUserActivityState( activity: NSUserActivity) { super.updateUserActivityState(activity) let newValues = [ “example.data”: [“data 1”, “data 2”] ] activity.addUserInfoEntriesFromDictionary( [“exemplo.keys”: newValues] ) } // restaura o estado da activity override func restoreUserActivityState(activity: NSUserActivity){ super.restoreUserActivityState(activity) let userInfo = activity.userInfo! //TODO: carregar as informações na tela }}

Listagem 4. Utilização do método prepareForInterfaceBuilder().

override func prepareForInterfaceBuilder() { if count(self.name) == 0 { self.name = “Azul” }}

Figura 6. Atributo Designables no Identity Inspector

Figura 7. Propriedade color anotada com @IBInspectable

Outra funcionalidade interessante do live rendering é a possi-bilidade de mostrar dados de exemplo no caso de componentes que mostram dados, como ocorre em componentes padrão como o picker view. Para isto, basta sobrescrever o método prepareForInterfaceBuilder() em sua classe como mostrado na Listagem 4.

Handoff Uma das funcionalidades mais comentadas do iOS 8, o Handoff

permite que o usuário continue seu trabalho de onde parou em qualquer dispositivo, seja iPhone, iPad e até mesmo OS X. Ele utiliza internamente o novo protocolo Bluetooth LE 4.0, suportado apenas em dispositivos mais atuais. Além disto, o usuário precisa

necessariamente estar logado na mesma conta do iCloud em todos os dispositivos que deseja utilizar.

Todo este processo ocorre através do user activity, um objeto que armazena as informações que serão transferidas entre os dispositivos.

Dentro deste objeto podem ser trafegados outros objetos encapsu-lados em um dicionário. Diversos objetos como NSArray, NSDic-tionary, NSString e quase todo objeto que implementa o protocolo NSCoding pode ser utilizado, ou seja, se você consegue serializar seu objeto em uma plist, é possível utiliza-lo em um user activity.

O handoff permite apenas três tipos de interação: criar, atualizar e continuar uma atividade. Na Listagem 5 podemos verificar estas interações pelos métodos startActivity, responsável pela criação de activity, o método updateUserActivityState, onde o desenvolvedor tem a chance de atualizar o estado da activity e o método restoreU-serActivityState, que será executado em outros dispositivos para permitir que o trabalho continue de onde se iniciou.

Page 10: Mobile 067 Asqgbnyu

Conheça as novidades do iOS 8

10 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia PB

WebKitO WebKit trata-se de um framework que veio para substituir

o componente UIWebView. Para muitos, pode não parecer uma grande novidade, porém, se você já precisou criar aplicações híbri-das ou webapps, esta novidade com certeza é de grande ajuda, pois é um framework criado para solucionar o problema de diversos desenvolvedores, que reclamavam da performance e limitações do UIWebView, pois agora este utiliza o mesmo motor de execução de JavaScript do navegador Safari, o Nitro.

As seguintes funcionalidades diferenciam o WebKit do UIWeb-View:• key-value observing (KVO): permite o monitoramento do car-regamento das páginas, permitindo ao desenvolvedor atualizar sua interface de acordo com o estado de carregamento;• gestures: como ocorre em componentes que herdam do UIView, o WebKit permite registrarmos diversas gestures, melhorando a usabilidades de nossos aplicativos;• scroll: o scroll das páginas no UIWebView possuía uma per-formance ruim, com o WebKit, a aceleração é feita por hardware, acabando com este problema de desempenho.• bridge nativo: através da API User Scripts e Script Messages, permite uma comunicação quase que perfeita entre o código nativo e o JavaScript das páginas.

O WebKit é a confirmação de que no futuro teremos webapps com qualidade semelhante, já que temos grandes empresas como o Facebook apoiando esta iniciativa com o lançamento de frameworks como o React Native, que permite o desenvolvimento de aplicações nativas utilizando JavaScript.

Sem dúvidas, com o lançamento do iOS 8, a Apple permitiu que os desenvolvedores dessem um salto em direção a produtividade, disponibilizando ferramentas que permitem a criação de aplica-ções de uma maneira rápida e prática.

Além disso, o lançamento da linguagem Swift, que além de trazer novos paradigmas para o mundo iOS, que diferente do Objective-C, possui uma abordagem menos verbosa e permite que façamos mais com menos código.

alexandre oliveira http://www.alexandresoli.com.brÉ especialista em mobilidade e entusiasta sobre tecnologia e inovação, além de gamer em suas horas vagas.

autor

links:

app Extensionshttps://developer.apple.com/app-extensions/

Documentação do CloudKithttps://developer.apple.com/icloud/documentation/cloudkit-storage/

Documento do Scene Kithttps://developer.apple.com/library/ios/documentation/SceneKit/Reference/SceneKit_Framework/index.html

ioS 8 for Developershttps://developer.apple.com/ios8/

Página do WatchKithttps://developer.apple.com/watchkit/

Página da linguagem Swifthttps://developer.apple.com/swift/

React nativehttps://facebook.github.io/react-native/

Dê seu voto em www.devmedia.com.br/webmobile/feedback

Ajude-nos a manter a qualidade da revista!

você gostou deste artigo?

Page 11: Mobile 067 Asqgbnyu

PB Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 11

Neste artigo serão apresentadas algumas novidades para os desen-

volvedores de aplicativos para o sistema iOS da Apple. Será discutido

como realizar a instalação da IDE Xcode e quais são os requisitos para

programar com a nova linguagem da Apple, o Swift. Em seguida

apresentaremos vários recursos presentes na Swift considerando sua

sintaxe, como declarar variáveis simples e opcionais, funções, variáveis

tipadas, constantes, classes, construtores e métodos e atributos de

uma classe. Para exemplificar os recursos da linguagem, criaremos

algumas classes Swift que simulam um PDV virtual para venda de

produtos, sendo necessário informar os dados do um cliente através

da passagem de parâmetro utilizando objetos. A discussão deste

tema é útil porque permitirá a você a iniciar o desenvolvimento de

aplicações iOS utilizando a nova linguagem de programação dispo-

nibilizada pela Apple.

Fique por dentro

Desenvolvendo em Swift com Xcode e iOS 8Aplicativos que rodam no iOS nos dispositivos

iPhone e iPad eram, até certo tempo atrás, de-senvolvidos com a linguagem de programação

Objective-C. Mais recentemente, a Apple criou uma nova linguagem para o iOS e OS X, a linguagem Swift, que demonstra ser mais intuitiva e produtiva para os desenvolvedores, isso sem comentar a simplicidade de desenvolver aplicativos utilizando ela.

Segundo a Apple, o iOS 8 é a versão com mais recursos para desenvolvedores desde o lançamento da App Store. Vejamos a seguir algumas novidades para os desenvolve-dores e usuários em relação aos recursos e novas APIs:• Aumento do número das opções de compartilhamento para que usuários tenham mais lugares para compar-tilhar o que for necessário como fotos, vídeos, sites e outros conteúdos com sites de mídia social, como o Facebook e o Twitter;• Possibilidade de colocar marca d’água em documentos, adicionar um item a uma lista de desejos ou traduzir um texto;• A central de notificações também teve melhorias, por exemplo, o desenvolvedor pode adicionar widgets que avisam e mostram o status de uma app;• Os desenvolvedores podem criar novos teclados que o usuário instala e usa em todo o seu sistema. Uma vez que eles estejam disponíveis, pode ser escolhido o layout ou modo de digitar preferido do usuário.

Também foram inseridos novos kits e APIs para desen-volvedores de jogos, possibilitando a criação de jogos 2D ou 3D com maior aproveitamento de processamento. Vejamos a seguir alguns dos principais kits de desen-volvimento de jogos no iOS 8:• Metal: os desenvolvedores podem criar jogos de alta complexidade. Ele foi aprimorado para que a CPU e a GPU trabalhassem em conjunto para chegar ao melhor desempenho possível. O Metal também foi estruturado para multithreading e vem com várias ferramentas para definir tudo que for necessário com a IDE Xcode;

• SpriteKit: os desenvolvedores criam jogos em 2D de alto de-sempenho, mas que consomem menos bateria. O iOS 8 traz vários aperfeiçoamentos que deixam os jogos em 2D ainda melhores. Essas novas tecnologias ajudam os personagens dos jogos a se movimentar com mais naturalidade. Fica mais fácil para os de-senvolvedores colocar campos de força, detectar colisões e gerar novos efeitos de iluminação nos jogos;• SceneKit: permite renderizar cenas de jogos em 3D para efeitos mais casuais. Ele possui mecanismos e maneiras mais fáceis para definir as ações de objetos em 3D. Além disso, os desenvolvedores podem tirar proveito da total integração com o SpriteKit e usar seus materiais nos jogos em 3D.

Outra novidade é a Swift. Ela é uma nova linguagem de progra-mação desenvolvida pela Apple para que desenvolvedores possam desenvolver apps facilmente para dispositivos com sistema da Apple, neste caso para os sistemas iOS e MAC OS X. Trata-se de uma linguagem com características para o desenvolvimento de aplicações robustas. Fazendo uma pequena comparação entre a linguagem Objective-C e Swift, o Swift apresenta uma sintaxe mais agradável para programar e é de fácil aprendizado por parte

Page 12: Mobile 067 Asqgbnyu

Desenvolvendo em Swift com Xcode e iOS 8

12 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 13 12 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 13

de programadores iniciantes e também para quem vem de outras linguagens de programação.

Um ponto importante a ser destacado no desenvolvimento com Swift é que se pode facilmente agregar bibliotecas desenvol-vidas em Objective-C em projetos com Swift. Desta forma, você pode facilmente aprimorar suas Apps com Swift.

Projeto de exemplo Swift com ioS 8 no simulador do iPhone

Antes de iniciamos a configuração necessária para o desenvolvimento de aplicações com Swift e iOS 8, é importan-

Figura 2. Definindo informações do projeto Xcode para iOS e iPhone

Figura 1. Template Xcode para iOS com Tabbed Application

te conhecer o Xcode e os requisitos para desenvolver os apps.

Xcode é a IDE para desenvolvimento de aplicações para os sistemas iOS e MAC OS X da Apple, ou seja, é uma IDE robusta e veio substituir o antigo ambiente de desenvolvi-mento da Apple, o Project Builder. Com Xco-de podemos criar aplicações facilmente com uso das linguagens Objective-C e Swift.

A linguagem de programação Swift foi introduzida no Xcode a partir da versão 6, sendo assim você também precisará da versão OS X 10.9 Mavericks ou superior para rodar o Xcode 6 com a linguagem Swift. Neste artigo iremos demonstrar

seus recursos com o OS X 10.10 Yosemite e Xcode 6.1.1. Caso você tenha uma versão anterior do MAC OS X, você pode atualizar gratuitamente o seu sistema operacional a partir do aplicativo App Store presente no MAC. O Xcode pode ser baixado dire-tamente da App Store. Logo em seguida você pode abrir o Xcode.

Criando um projeto Swift no XcodeAo iniciar o Xcode, temos algumas opções

para criar um projeto. A primeira opção, o botão Get started with a playground, cria um playground que permite escrever um código rapidamente com Swift para iOS ou OS X. Selecionada esta opção, você terá poucas configurações e o layout do Xcode é simplificado mostrando ao lado da janela principal o resultado da execução do código. Já a segunda opção, o Create a new Xcode Project, cria um novo projeto no Xcode que permite você selecionar um template para os sistemas iOS ou OS X. Selecionada esta opção você terá uma visualização completa da estrutura e controle total do seu projeto.

Para criamos o primeiro projeto no Xcode vamos escolher a segunda opção “Create a new Xcode project” e selecionar o template para iOS Tabbed Application, conforme apresentado na Figura 1, para criar uma aplicação com navegação por tabs.

Selecionado o template Tabbed Appli-cation, clique em Next e em seguida será apresentada uma tela conforme mostra a Figura 2. No primeiro campo você deve in-formar o nome de seu projeto. Neste exemplo informamos App_iOS_Tabbed. No segundo campo deve ser informada a organização que está desenvolvendo a App, neste caso informamos DEVMEDIA. Já no terceiro campo devemos informar o identificador da organização. Em seguida deve ser infor-mada a linguagem que se deseja utilizar no desenvolvimento da App. Aqui você pode escolher as linguagens Objective-C e Swift. Neste exemplo iremos utilizar Swift.

No último campo você deve informar que tipo de dispositivo sua aplicação vai rodar. Você tem as opções iPhone e iPad, porém se sua aplicação vai precisar rodar nos dois tipos de dispositivos, você deve selecionar a opção universal. Em nosso exemplo iremos selecionar iPhone.

Page 13: Mobile 067 Asqgbnyu

12 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 13 12 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 13

Feito isso, você deve clicar em Next. O próximo passo será defi-nir o local onde as informações do projeto serão salvas. Ao final desta etapa basta selecionar a opção create. Criado o projeto, será apresentada a tela do Xcode com o projeto recém-criado aberto conforme ilustra a Figura 3. Aqui você ainda pode informar alguns dados adicionais sobre seu projeto como a versão da aplicação, selecionar um ícone para a App, versão do iOS para publicação (neste caso selecione a versão 8), dentre outras.

Antes de rodar o aplicativo, você deve selecionar que tipo de dispositivo deve ser emulado no iOS Device. Para isso, configure o scheme localizado ao lado da opção stop na parte superior da tela do Xcode. Para isso, selecione Ative scheme> iOS Device> iPhone 6 conforme ilustra a Figura 4.

Neste momento, clique no botão Run e visualizar o resultado conforme Figura 5. Perceba que na parte inferior do simulador do iOS existem duas abas para que você possa alternar entre duas telas (cada uma representando uma aba do projeto) que são criadas por padrão quando é selecionado um template do tipo Tabbed Application.

Caso seu simulador fique muito grande para visualizar por completo na tela de seu MAC, então você deve recorrer às se-guintes opções:1. Scale – Geralmente quando o simulador é executado pela pri-meira vez, a opção scale vem configurada para 100%. Desta forma,

Figura 3. Projeto recém-criado com Swift aberto no Xcode

Figura 4. Selecionando o device para iPhone 6

a tela pode ficar muito grande e, de acordo com a resolução do seu MAC, tendo até que usar a barra de rolagem do device. As-sim, é possível alterar a resolução para 75% ou 50% e melhorar a visualização do device. Para realizar a alteração da scale deixe a tela do device ativa e no menu Window> Scale você pode mudar a escala;2. Resizable – Na opção iOS Device existem duas novas opções, o Resizable iPad e Resizable iPhone, que possibilitam definir dife-rentes tamanhos de tela para simular a execução de sua aplicação em dispositivos com tamanhos de tela diferentes;

Page 14: Mobile 067 Asqgbnyu

Desenvolvendo em Swift com Xcode e iOS 8

14 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 15 14 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 15

Figura 5. Aplicação em Tabbed rodando no device iPhone 6

Figura 6. Projeto Command Line Tool com Swift

3. Teclas de atalho – Outra facilidade para ajustar o tamanho da tela do simu-lador seria utilizar as teclas de atalhos command+1, command+2 e command+3.

Caso precise testar a visualização de sua aplicação com simuladores do iPhone e iPad na horizontal ou vertical, você pode usar as teclas de atalho command + seta para esquerda e command + seta para direita.

Swift na práticaAgora iremos passar a explorar a lin-

guagem de programação Swift criando um novo projeto de exemplo. Crie um novo projeto através do menu File> New> Project> OS X> Application> Command Line Tool. As definições do novo projeto podem ser vistas na Figura 6. Criaremos um projeto linha de comando.

Veja agora na Figura 7 o projeto Com-mand Line Tool criado. Perceba que no lado esquerdo da janela do Xcode temos os arquivos que compõem a estrutura do projeto e ao lado direito da IDE temos algumas propriedades do projeto.

No momento temos aberto para edição o arquivo main.swift que é o ponto de partida para a execução do projeto. Caso você execute com o comando Run na parte superior da janela do Xcode, será apresen-tada como saída da execução a mensagem “Hello, World!” conforme exibido na parte inferior na janela do Xcode presente na Figura 7.

É importante citar que o Xcode criou o projeto e adicionou algumas linhas de código como exemplo informando alguns comentários que são destacados na cor verde e indicados com // no começo da linha. Perceba que após o comentário foi realizado um import da biblioteca Foundation que contém um conjunto de classes escritas em Objecitve-C. Por fim é chamada a função println que recebe como

parâmetro uma string para que possa ser exibida na tela.

Agora vamos realizar algumas alterações no código gerado pelo Xcode de forma que possamos entender como declarar e inicializar variáveis no Swift. Por fim, iremos utilizar a função println para exibir as informações na tela.

A Listagem 1 apresenta a alteração do código do arquivo main.swift. Perceba que nas linhas 11 e 12 foram declaradas e inicializadas duas variáveis. Para isso foi utilizada apenas a palavra reservada “var”. Não é necessário informar o tipo de dado a ser utilizado pois a linguagem Swift tem tipagem fraca. É no momento da compilação do código que será definido o tipo de cada variável declarada de acordo com o valor atribuído a ela. Se você tentar declarar uma variável em uma linha e inicializá-la na próxima linha, será gera-do um erro em tempo de compilação do código fonte.

Outro ponto importante a destacar na linguagem é que não é necessário colocar “;” no final de cada linha pois a Swift trabalha com endentação e vai entender cada linha como uma instrução distinta a ser executada.

Perceba na linha 14 que o uso da função println recebe duas expressões dentro de uma string utilizando a sintaxe \(variável) para exibir na tela os valores das variáveis nome, que é uma string e idade é que do tipo inteiro.

Listagem 1. Declaração e inicialização de variáveis.

01 //02 // main.swift03 // PraticaSwift04 //05 // Created by madsonadm on 2/9/15.06 // Copyright (c) 2015 DEVMEDIA. // All rights reserved.07 //08 09 import Foundation1011 var nome = “Antônio Pedro”12 var idade = 271314 println(“Seu nome é: \(nome) e sua idade é: \(idade)”)

Page 15: Mobile 067 Asqgbnyu

14 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 15 14 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 15

Figura 7. Projeto Command Line Tool criado

Funções, variáveis tipadas e constantesCom Swift podemos organizar melhor o código e definir

algumas funções para separar trechos de código e suas res-ponsabilidades. Funções podem ser chamadas facilmente, sem falar que este recurso possibilita o reaproveitamento de código. Não se preocupe se você programa com uma linguagem cem por cento orientada a objetos, pois com Swift também pode-mos criar estrutura de classes e métodos como veremos mais adiante neste artigo.

Analisando a Listagem 2 você pode entender melhor o con-ceito de função, variáveis tipadas e constantes. Da linha 2 até a 6 foi realizado um comentário de múltiplas linhas utilizando /* para iniciar o comentário e */ para finalizar. Na linha 9 foi criada uma função com sintaxe func nome_da_função(). Quan-do precisar criar uma função, você deverá utilizar a palavra reservada func seguida pelo nome da função, dois parênteses que podem ou não receber valores por parâmetro e, por fim, usar pares de chaves para delimitar o escopo do bloco de códi-go pertencente à função. Caso seja necessário retornar algum valor ao chamador da função, então deve ser informado após os parênteses o tipo de retorno e utilizar a palavra return ao final do corpo da função.

Nas linhas 10 e 11 foram declaradas duas varáveis utilizando a palavra reservada var, porém há um detalhe na declaração destas variáveis: após o nome da variável foi colocado dois pontos e o tipo de dado da variável, desta forma temos a decla-

ração de variáveis fortemente tipadas. Este procedimento gera dois ganhos: o código fica mais compreensível para a leitura ao saber que tipo de dado é usado nas variáveis e o compilador irá ganhar tempo pois não precisa analisar o valor atribuído à variável para identificar o tipo.

Listagem 2. Função, variáveis tipadas e constantes

01 import Foundation02 /*03 var nome = “Antônio Pedro”04 var idade = 2705 println(“Seu nome é: \(nome) e sua idade é: \(idade).”)06 */07 08 //Definição de função com constantes09 func funcVarTipadaConstante(){10 var produtoDescricao:String = “Refrigerante laranja 2L”11 var qtdeEstoque:Int = 1812 let unidadeMEdida:String = “kg”13 14 println(“Descrição produto: \(produtoDescricao) - Qdte estoque: \(qtdeEstoque)”)15 println(“Venda de 10 kg... Estoque disponível: \(qtdeEstoque - 10)”)16 17 qtdeEstoque = qtdeEstoque - 1018 }19 20 funcVarTipadaConstante()

Page 16: Mobile 067 Asqgbnyu

Desenvolvendo em Swift com Xcode e iOS 8

16 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 17 16 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 17

Na linha 12 temos a definição de uma constante com uso da palavra reservada let. Uma constante pode ser considerada como uma variável imutável, pois após atribuir um valor à mesma o valor não vai mudar. Caso você tente atribuir um novo valor a uma constante, ocorrerá um erro em tempo de compilação. Nas linhas 14 e 15 exibimos na tela os dados do produto e em seguida simulamos uma venda exibindo quanto vai restar em estoque após a realização da venda. Na linha 17 decrementamos a quantidade vendida da variável qtdeEstoque. Por fim, na linha 20 realizamos a chamada da função funcVarTipadaConstante que irá executar o trecho de código da linha 11 até a 17.

Veja na Figura 8 o resultado da execução da Listagem 2 que apresenta a descrição do produto, quantidade em estoque do produto, informação da venda e itens do produto vendido. Por fim, é exibida a quantidade restante em estoque após dedução da quantidade vendida.

variáveis opcionaisNão é possível utilizar variáveis simples não inicializadas no Swift,

pois caso seja feito será gerado um erro em tempo de execução. Entre-tanto, há casos em que realmente é necessário trabalhar com variáveis onde, durante a execução do código, seu valor seja nulo, ou nil em Swift. Assim sendo, no Swift existe a possibilidade de trabalhar com variáveis nulas, um recurso conhecido como variável Optional.

Para entendermos melhor sobre o uso de variáveis opcionais, veja na Listagem 3 o bloco de código da função funcVar-Opcional() que apresenta logo na linha 3 a declaração de um variável denominada varOpcional. É importante destacar nesta linha que foi informado o tipo de dado que a variável irá receber e logo após foi colocado uma “?”. Esta é a sintaxe para definirmos uma variável opcional (que pode conter valor nulo durante a execução do código sem gerar um erro em tempo de compilação).

Outro ponto importante a destacar na Listagem 3 é que na linha 5 é realizado um teste para verificar se a variável varOpicional é nula. Se a condição for verdadeira, exibimos na tela a mensagem da linha 6. Na linha 9 é inicializada a variável varOpicional e na linha 10 é exibido o valor contido dentro da variável opcional na tela. Por fim, na linha 13 é chamada a função funcVarOpcional() para executar o bloco de código.

Na linha 10 foi utilizada a “!” depois do nome da variável para exibir o valor contido na variável opcional. Este procedimento é conhecido como unwrapping. Caso você não queria usar ! depois do nome das variáveis opcionais, você pode simplesmente usar ! no lugar de ? em sua declaração. Desta forma você força a exibição do valor apenas chamando-a pelo nome. Este procedimento é conhecido como force unwrapping do Swift.

Para melhor entendimento da execução da Listagem 3, veja na Figura 9 o resultado de saída após a execução do código desta listagem.

Trabalhando com classes no SwiftPodemos trabalhar com classes, métodos e objetos na linguagem

Swift. Embora até aqui tenhamos falado sobre criação de função,

Figura 8. Execução de código de exemplo de função, variáveis tipadas e constantes

Figura 9. Exemplo de código da variável opcional

Listagem 3. Uso de variável opcional

01 import Foundation02 func funcVarOpcional(){03 var varOpcional:String?04 05 if(varOpcional == nil){06 println(“A variável não foi inicializada: \(varOpcional)”)07 }08 09 varOpcional = “Este é o valor da variável opcional.”10 println(“A variável foi inicializada: \(varOpcional!)”)11 }12 13 funcVarOpcional()

você verá que para declarar métodos dentro de uma classe vamos seguir o mesmo procedimento.

Os arquivos em um projeto com Swift têm a extensão .swift. Isto não será diferente para um arquivo que representa uma classe. Para criar uma classe no projeto atual é bem simples: menu File> New> File...> iOS/OS X> Source> Swift File. Após selecionado Swift File, você deve informar os dados para criar uma classe conforme ilustra a Figura 10 que define uma classe com nome Cliente.

A classe cliente foi criada, porém o arquivo Cliente.swfit ainda não tem a estrutura de uma classe. A sintaxe para definir a es-trutura de uma classe é: class nome_da_classe { aqui dentro são definidas as propriedade da classe e seus métodos }.

Veja na Listagem 4 a estrutura definida para a classe que irá representar objetos do tipo cliente. Logo na linha 11 foi informada a palavra reservada class seguida pelo nome da classe. Da linha 13 até 17 são definidas algumas propriedades para armazenar dados do cliente. Perceba ainda que utilizamos a mesma sintaxe de de-claração de variáveis nas propriedades da classe. Elas também são definidas como opcionais pois ao criarmos uma instância desta classe não iremos inicializá-la logo no seu carregamento.

Da linha 18 até 20 temos a definição do construtor padrão da classe cliente. O método padrão é chamado automaticamente quando for criado um objeto desta classe.

Page 17: Mobile 067 Asqgbnyu

16 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 17 16 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 17

Figura 10. Criando a classe cliente

Criada a estrutura da classe cliente, agora veremos como podemos utilizá-la. Será criado um objeto, uma instância da classe, para que se possa manipular dados de um cliente ou uma lista do mesmo. Para exemplificar, será modificado o ar-quivo main.swift, conforme a Listagem 5. Na linha 2 foi criada uma função chamada funcTestandoClasseCliente(). Na linha 3 foi criada uma instância da classe cliente apenas definindo um objeto que recebe uma instância de cliente pela chama-da Cliente(). Da linha 5 até 9 são atribuídos os valores das propriedades do novo objeto cliente com nome de objClasse- Cliente. Nas linhas 11 a 16 são mostrados na tela os dados do cliente com uso da função println. Por fim, na linha 19 é chamada a função funcTestandoClasseCliente.

Veja na Figura 11 a saída no console referente à execução do código.

Listagem 4. Estrutura da classe cliente

01 //02 // Cliente.swift03 // PraticaSwift04 //05 // Created by madsonadm.06 // Copyright (c) 2015 DEVMEDIA. All rights reserved.07 //08 09 import Foundation10 11 class Cliente {12 13 var nome:String?14 var idade:Int?15 var cpf:Int?16 var rg:Int?17 var endereco:String?18 init(){19 //Construtor padrão da classe cliente20 }21 }

Construtores de classe no SwiftConstrutor é um método que é executado automaticamente

quando se instancia um objeto a partir de uma classe. Uma classe pode conter vários construtores diferentes. Por exemplo, na classe cliente apresentada tínhamos um construtor padrão, o init(), po-rém é possível criar um construtor personalizado que possa até receber parâmetros para realizar uma determinada tarefa após criar a instância da classe.

Para exemplificar melhor como usar um construtor em uma classe, será criada uma nova classe no projeto seguindo os mesmos passos usados na criação da classe cliente, conforme a Listagem 6. Será criada uma classe chamada produto e a mesma deve ini-cializar suas propriedades com as características do produto no momento da instanciação da classe através da chamada do construtor personalizado.

Podemos notar a personalização do construtor padrão init() a partir da linha 17 até 21. Perceba que agora o construtor padrão recebe três valores por parâmetro e em seguida inicializa as variáveis declaradas entre as linhas 12 e 14. Nesta listagem não foi usada variável opcional pois o construtor padrão inicializa as variáveis no momento da instanciação da classe.

Também foi inserido um trecho de código no arquivo main.swift. Foi criada uma função chamada TesteClasseProduto e na linha 4 (Listagem 7) é criado um objeto instanciando a classe produto passando por parâmetro os dados dos produtos para o construtor padrão. Por fim, na linha 6 são apresentadas na tela as informações do produto através da função println.

Figura 11. Execução de código de teste da classe cliente

Listagem 5. Instanciando a classe cliente.

01 import Foundation02 func funcTestandoClasseCliente(){03 var objClasseCliente = Cliente()04 05 objClasseCliente.nome = “João Pedro”06 objClasseCliente.idade = 1807 objClasseCliente.cpf = 12345678908 objClasseCliente.rg = 123525355209 objClasseCliente.endereco = “Rua Alfa - Centro - 42”10 11 println(“Dados cliente:”)12 println(“Nome: \(objClasseCliente.nome!)”)13 println(“Idade: \(objClasseCliente.idade!)”)14 println(“CPF: \(objClasseCliente.cpf!)”)15 println(“RG: \(objClasseCliente.rg!)”)16 println(“Endereço: \(objClasseCliente.endereco!)”)17 }1819 funcTestandoClasseCliente()

Page 18: Mobile 067 Asqgbnyu

Desenvolvendo em Swift com Xcode e iOS 8

18 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 19 18 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 19

Observe na Figura 12 o resultado da execução do código apresentado.

Listagem 6. Definição da classe produto.

01 //02 // Produto.swift03 // PraticaSwift04 //05 // Created by madsonadm.06 // Copyright (c) 2015 DEVMEDIA. All rights reserved.07 //08 09 import Foundation10 11 class Produto {12 var nome:String13 var preco:Double14 var qtdeEstoque:Int15 16 //Construtor padrão17 init(_nome:String, _preco:Double, _qtdeEstoque:Int){18 nome = _nome19 preco = _preco20 qtdeEstoque = _qtdeEstoque21 }22 }

Listagem 7. Definição da classe produto.

01 import Foundation02 03 func TesteClasseProduto(){04 var objProduto = Produto(_nome: “Suco uva 300ml”, _preco: 2.9, _qtdeEstoque: 89)05 06 println(“Produto: \(objProduto.nome), preço: \(objProduto.preco), estoque: \(objProduto.qtdeEstoque)”)07 }08 09 TesteClasseProduto()

Figura 12. Execução do código com uso da classe produto

Definindo métodos com parâmetros em uma classeOs métodos estão presentes na estrutura da classe e são respon-

sáveis por um comportamento específico. Para exemplificarmos o conceito de métodos, criaremos uma nova classe chamada venda que será responsável por realizar a venda de produtos aos clientes

O primeiro passo é criar a classe venda conforme apresentado na Listagem 8. Na linha 4 foi criado um atributo para a classe do tipo Cliente (você pode ter propriedades em uma classe que sejam do tipo de outra classe existente). Nas linhas 6 a 8 temos o construtor padrão que, neste caso, recebe como parâmetro um

objeto do tipo cliente. Na linha 7 é atribuído o objeto cliente re-cebido por parâmetro à propriedade definida na linha 4. Perceba que para receber algo por parâmetro você deve seguir a sintaxe: nome_paramentro:TipoDado.

Na linha 10 foi definido um método para a classe venda. A defi-nição de um método segue a mesma sintaxe de uma função: func nome_metodo(lista_de_parametros) -> tipo_de_retorno { return valor_retornado }. Da linha 12 a 16 temos a implementação do método vendaProduto que recebe como parâmetro um objeto do tipo produto e a quantidade de venda do produto. Perceba ainda que este método retorna um valor do tipo Double ao chamador e este valor representa o total da venda a ser pago pelo cliente.

No escopo do método vendaProduto foi usada várias vezes a função println para simular a impressão de um cupom fiscal para o cliente. Vale destacar que na linha 13 usamos “!” para mostrar os valores contidos nas propriedades do objeto tipo produto pois suas propriedades são opcionais. Na linha 14 mostramos o item vendido e a quantidade recuperando as informações do objeto produto que foi recebido por parâmetro. Na linha 15 foi criada uma variável chamada valorTotal que recebe o cálculo do valor total da venda. Por fim, na linha 16 é informada a palavra reservada return para que possa retornar um valor ao chamador deste método.

Para finalizar o estudo sobre método em classes, vamos analisar a Listagem 9 que apresenta como usar e chamar o método criado na classe venda. Este código foi inserido no arquivo main.swift e logo na linha 3 é criada uma função chamada funcRealizarVenda(). Na linha 4 foi instanciado um objeto do tipo cliente para represen-tar um cliente na abertura de uma venda. Perceba que nas linhas 5 a 9 são atribuídos valores aos atributos do objeto cliente através do nome do objeto mais o nome da propriedade.

Na linha 11 é criado o objeto chamado objVenda que simula a abertura de uma venda. Perceba que é passado no construtor da classe venda um objeto do tipo cliente para utilizar no construtor da classe cliente. Logo após, na linha 13, é instanciado mais um

Listagem 8. Definição da classe venda.

01 import Foundation02 03 class Venda{04 var cliente:Cliente05 06 init(_cliente:Cliente){07 cliente = _cliente08 }09 10 func vendaProduto(_produto:Produto, _qtdeVenda:Double) -> Double{11 12 println(“-------PDV-------”)13 println(“Cliente: \(cliente.nome!), CPF: \(cliente.cpf!)”)14 println(“Item: \(_produto.nome) - Qtde: \(_qtdeVenda)”)15 var valorTotal:Double = _qtdeVenda * _produto.preco16 return valorTotal17 }18 }

Page 19: Mobile 067 Asqgbnyu

18 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 19 18 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 19

objeto do tipo produto para representar o item vendido. Perceba que também são passados valores pelo construtor padrão da classe produto.

O mais importante vem na linha 15, onde é realizada a chamada ao método vendaProduto do objeto objVenda. Neste método tam-bém é passado um objeto do tipo produto e quantidade vendida por parâmetro. Por fim, na linha 17 é mostrado na tela o total da venda atribuído à variável da linha 15 pelo valor retornado do método vendaProduto.

Como vimos, o desenvolvimento de aplicações iOS ficou ainda mais prático e produtivo. O Swift traz uma série de facilidades que vieram, muitas vezes, para suprir lacunas deixas pelo Objective-C. Neste artigo conhecemos algumas das características dessa nova

forma de programar para iOS. Muitos dos tópicos discutidos valem um material dedicado a eles. Mas agora que já apresenta-mos uma visão geral sobre as novidades, você está pronto para explorar as novas facilidades em suas aplicações. Essa é a única maneira de conhecer totalmente os benefícios trazidos com a nova linguagem da Apple.

Listagem 9. Código para venda de produto

01 import Foundation02 03 func funcRealizarVenda(){04 var objCliente = Cliente()05 objCliente.nome = “Carlos Alberto”06 objCliente.cpf = 123456707 objCliente.rg = 6526546508 objCliente.idade = 2109 objCliente.endereco = “Rua Paulo Afonso”10 11 var objVenda = Venda(_cliente: objCliente)12 13 var objProduto = Produto(_nome: “Arroz branco”, _preco: 2.8, _qtdeEstoque: 320)14 15 var total = objVenda.vendaProduto(objProduto, _qtdeVenda: 8)16 17 println(“Valor Total: \(total)”)18 }19 20 funcRealizarVenda()

Madson aguiar [email protected]ção acadêmica em Análise e Desenvolvimento de Sistemas pela UNOPAR, pós-graduação em Engenharia de Sistemas pela ESAB e especialista em Tecnologias para aplicações Web pela UNOPAR. Trabalha com desenvolvimento de software há sete anos

com uso a da plataforma .NET, JAVA e Mobile com Android. Atua no mercado com pres-tação de serviços e consultoria em TI, fornecendo soluções em software, tutor do curso de graduação em Análise e Desenvolvimento de Sistemas na UNOPAR e autor artigos e vídeo no portal DEVMEDIA.

autor

links:

novidades ioS 8https://www.apple.com/br/ios/developer/

a linguagem Swifthttps://www.apple.com/br/swift/

Dê seu voto em www.devmedia.com.br/webmobile/feedback

Ajude-nos a manter a qualidade da revista!

você gostou deste artigo?

Page 20: Mobile 067 Asqgbnyu

20 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 21 20 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 21

O JPDroid é um framework que permite o mapeamento objeto

relacional na plataforma Android. Através dele é possível ganhar

produtividade no desenvolvimento de aplicações que necessitam

persistir objetos no banco de dados SQLite. Neste artigo veremos o

desenvolvimento de uma aplicação que contém várias telas e tabelas

relacionadas entre si. Esta característica nos permitirá apresentar

muitos dos recursos disponibilizados pelo framework. Assim, através

deste artigo você estará apto a utilizar o JPDroid em diferentes situ-

ações do dia a dia onde persistir os dados de sua aplicação Android

seja um requisito básico.

Fique por dentro

Introdução ao Framework ORM Android JPDroid – Parte 2

Devido ao aumento do uso da plataforma mobile, assim como o aumento no poder de processa-mento e armazenamento dos devices Android,

muitos frameworks objeto-relacional estão à disposição dos programadores, e um que merece grande destaque é o Jpdroid, que se destaca pela facilidade de uso e seus inúmeros recursos.

Este artigo apresenta um exemplo completo de sistema Android com uso de banco de dados. O exemplo contém várias telas e tabelas relacionadas entre si, permitindo um uso quase que completo do framework. Para o desen-volvimento do aplicativo, o usuário deve ter instalado e configurado o kit de desenvolvimento Android padrão formado pelo Eclipse, SDK e ADT.

Criando o ProjetoIremos desenvolver um aplicativo para gerenciamento

de contatos. O aplicativo possui três telas: tela principal, tela para cadastro de pessoa e cadastro de contato. A ideia é poder cadastrar pessoas e informar alguns contatos para ela, como telefone, celular ou e-mail. Este aplicativo nos permite trabalhar com o relacionamento de tabelas.

A Figura 1 apresenta o que será a tela principal do aplicativo, que apresentará ao centro a lista com todas as pessoas cadastradas. O usuário poderá, a qualquer momento, realizar um filtro nos registros cadastrados utilizando os componentes da parte superior da tela. Na parte inferior, o usuário poderá cadastrar uma nova pessoa no sistema, assim como realizar um backup ou restore do banco.

EstE artigo faz partE dE um curso

Além destas opções, o sistema contará com um menu de contexto. Ao dar um clique longo sobre um dos elementos da lista, um menu será apresentado permitindo editar ou excluir uma determinada pessoa, conforme apresentado na figura anterior.

Ao clicar no botão Adicionar Pessoa, ou ao escolher a opção excluir, uma nova tela de cadastro de pessoas será apresentada. No primeiro caso, esta tela aparecerá em branco e no segundo caso, aparecerá com o campo preenchido permitindo a alteração de dados, conforme apresenta a Figura 2.

No cadastro de pessoa, o nome será apresentado na parte supe-rior e os contatos cadastrados para esta serão vistos no ListView que será apresentado no centro da tela. Assim, uma pessoa pode ter nenhum ou vários contatos (por exemplo: número de telefone, número de celular e e-mail).

Estes contatos podem ser gerenciados efetuando-se também um clique longo sobre estes. O sistema apresentará um menu de contexto que permite Editar ou Excluir um contato.

Ao optar por Editar um Contato ou clicando no Add Contato, uma nova tela é apresentada, conforme apresentado na Figura 2. Esta tela permite associar um novo contato, ou alterá-lo.

Page 21: Mobile 067 Asqgbnyu

20 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 21 20 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 21

Figura 1. Tela Inicial e Menu de contexto

Figura 2. Cadastro de Pessoa e de Contato

O cadastro de contato permite cadastrar três tipos de contato que serão apresentados no Spinner. Estes terão o código que segue: 1-Email, 2-Telefone, 3-Celular.

Para realizar backup da base selecione o botão backup. Quando realizado com sucesso, uma mensagem será exibida conforme mostra a Figura 3. Ao longo da execução do aplicativo, mensagens informativas serão apresentadas. Nesta figura temos as mensa-gens de sucesso para o Backup, assim como para confirmação de exclusão de registro.

Após realizar o backup e a exclusão de um registro, podemos restaurar os dados selecionando o botão restore. Observe que ao restaurar os dados do backup, os itens excluídos estarão dispo-níveis novamente.

Para melhorar este projeto, poderíamos enviar os dados de backup por e-mail, garantido desta forma que os dados fiquem

Figura 3. Mensagens de Sucesso/Confirmação

armazenados em um local seguro, ou ainda armazená-lo em algum respositório na núvem, porém, para não aumentar muito a complexidade do aplicativo, optou-se em apenas armazenar o backup no próprio dispositivo.

O primeiro passo para o desenvolvimento da aplicação é criar um projeto Android padrão. Para isso, abra o Eclipse e crie um novo projeto Android, através da opção File -> New -> Android Application Project. Feito isso, será apresentada a tela com as con-figurações de seu Android, conforme apresentado na Figura 4.

Configure estas propriedades de acordo com sua preferência. Para nome do projeto foi utilizado AndroidComJpdroid, o nome da activity principal é activity_main, sendo estes armazenados no pacote com.rafael.androidcomjpdroid.

Com o projeto criado, para iniciar o desenvolvimento utilizando o framework JPDroid é necessário baixar a biblioteca “jpdroid.jar” e adicioná-la ao “Build Path” do projeto.

associando biblioteca ao ProjetoPara vincular a biblioteca ao projeto, acesse o repositório

do framework (ver seção Links), navegue até o diretório “JPDROID_Jar”, localize a biblioteca “jpdroid.jar”e efetue o download.

Após baixar o framework, é aconselhável copiá-lo para a pasta libs do projeto. Após colar a biblioteca na pasta libs, a mesma deverá ser vinculada como uma biblioteca do projeto. Para isso, deve-se clicar com o botão direito sobre o projeto – Properties, na categoria Java Build Path deve-se escolher a aba Libraries. Na sequência, clica-se no botão Add JARs, selecionando o arquivo baixado da Internet, que se encontra na pasta libs do corrente projeto, conforme apresentado na Figura 5.

Desenvolvimento do aplicativoPara uma melhor organização do projeto, vamos criar um pacote

para armazenar as classes de entidades.

Page 22: Mobile 067 Asqgbnyu

Introdução ao Framework ORM Android JPDroid – Parte 2

22 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 23 22 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 23

Para isso, clique com o botão direito so-bre o pacote principal, escolhendo a opção New ... Package, na tela seguinte, informe o nome do pacote, que para o exemplo foi utilizado com.rafael.androidcomjpdroid

Figura 4. Configuração de um novo projeto Android

Figura 6. Criando o pacote para armazenar as classes de entidades.

Figura 5. Incluindo a biblioteca do framework ao projeto

.entity, finalizando no botão Finish, con-forme apresentado na Figura 6.

O próximo passo é a criação das classes de entidades, as quais representarão as tabelas no banco de dados.

Deve-se clicar com o botão direito sobre o pacote criado, escolhendo a opção New... Class.

Três classes devem ser criadas: Tipo-Contato, Contato e Pessoa. A classe de entidade TipoContato possui apenas dois atributos (_id e descricao). Esses seriam equivalentes aos campos da tabela Ti-poContato. Estes devem ter os métodos getters e setters, assim como as anotações que o definem como uma classe de enti-dade. O código completo é apresentado na Listagem 1. Para simplificar os códigos, as linhas referentes aos imports e também declaração de pacote foram omitidas. A maioria das IDEs já importa automatica-mente as classes à medida que está sendo codificado o programa.

A primeira linha da classe recebe a ano-tação @Entity. Desta forma, a classe será tratada como uma entidade no banco de dados. A chave primária deve ser sempre do tipo Long e nomeada como _id (linhas 6 e 7). O campo descrição (linha 11) também é declarado. Para finalizar a classe de enti-dade, os métodos getters e setters devem ser codificados (linhas 13 a 18).

A seguir o mapeamento da entidade Con-tato, que permitirá relacionar vários con-tatos a entidade Pessoa, é implementado. Seu código é apresentado na Listagem 2. Na linha 1 é definida a anotação @Entity para informar que esta classe é uma entidade. A chave primária, obrigatória, possui nome _id (linha 07).

O atributo idTipoContato (linha 11) é uma chave estrangeira que permite identificar o tipo do contato (Email, Telefone ou Celu-lar) – definida na classe Contato e que será codificada na sequência. A coluna nome-TipoContato (linha 15) é um atributo que não será persistido (anotação @Ignorable), sua única função é apresentar a descrição do contato proveniente da entidade Tipo-Contato, no componente ListView, também codificado posteriormente.

O atributo idPessoa (linha 19) é uma chave estrangeira que permite relacionar a Pessoa ao Contato cadastrado. Como parâmetros da anotação ForeignKey estão o nome da entidade, a chave de re-lacionamento existente na entidade, assim como se acontecerá exclusão em cascata

Page 23: Mobile 067 Asqgbnyu

22 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 23 22 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 23

Listagem 1. TipoContato.java – Classe responsável pelo mapeamento da entidade TipoContato.

01. @Entity02. public class TipoContato implements Serializable{03. 04. private static final long serialVersionUID = 1L;05. 06. @PrimaryKey07. @Column08. private Long _id;09. 10. @Column11. private String descricao;12. 13. public Long get_id() {14. return _id;15. }16. 17. public void set_id(Long _id) {18. this._id = _id;19. }20. 21. public String getDescricao() {22. return descricao;23. }24. 25. public void setDescricao(String descricao) {26. this.descricao = descricao;27. }28. }

01. @Entity02. public class Contato implements Serializable {03. private static final long serialVersionUID = 1L;04. 05. @PrimaryKey06. @Column07. private Long _id;08. 09. @ForeignKey(joinEntity=TipoContato.class,joinPrimaryKey=”_id”)10. @Column11. private Long idTipoContato;12. 13. @Ignorable14. @ViewColumn(entity=TipoContato.class,foreignKey=”idTipoContato”, atributo = “descricao”)15. private String nomeTipoContato;16. 17. @ForeignKey(joinEntity=Pessoa.class,joinPrimaryKey=”_id”,deleteCascade=true)18. @Column19. private Long idPessoa;20. 21. @RelationClass(relationType=RelationType.OneToMany, joinColumn=”idTipoContato”)22. private TipoContato tipoContato;23. 24. @Column25. private String contato;26. 27. public Long get_id() {28. return _id;29. }30. 31. public void set_id(Long _id) {32. this._id = _id;

33. }34. 35. public Long getIdTipoContato() {36. return idTipoContato;37. }38. 39. public void setIdTipoContato(Long idTipoContato) {40. this.idTipoContato = idTipoContato;41. }42. 43. public TipoContato getTipoContato() {44. return tipoContato;45. }46. 47. public void setTipoContato(TipoContato tipoContato) {48. this.tipoContato = tipoContato;49. }50. 51. public String getContato() {52. return contato;53. }54. 55. public void setContato(String contato) {56. this.contato = contato;57. }58. 59. public String getNomeTipoContato() {60. return nomeTipoContato;61. }62. 63. public void setNomeTipoContato(String nomeTipoContato) {64. this.nomeTipoContato = nomeTipoContato;65. }66. }

Listagem 2. Contato.class

(excluindo uma determinada Pessoa, automaticamente os contatos relacionados a esta também serão excluídos).

Para relacionar a entidade Contato ao TipoContato e definir a cardinalidade (um para muitos), é utilizada a anotação @Relation-Class (linha 21). O valor do contato será armazenado no atributo contato (linha 25). Por fim (linhas 27 a 65), os métodos getters e setters da classe.

A última entidade utilizada neste exemplo é Pessoa, que permite ao aplicativo cadastrar pessoas relacionando estas à entidade Contato, conforme apresenta a Listagem 3.

A estrutura dessa classe respeita a organização das demais entidades já apresentadas até o momento. A diferença está no atributo nome que armazena o nome da pessoa (linha 9). Para permitir relacionar vários Contatos a uma Pessoa, foi adicionada uma lista da entidade Contato (linha 26). A anotação @Relation-Class permite definir a cardinalidade (muitos para um) e qual atributo será a chave estrangeira utilizada para realizar a relação entre as classes como, por exemplo, o atributo idPessoa que está na entidade Contato.

Após codificar as entidades, o passo seguinte é a parametrização e a inicialização do framework de persistência. Aconselha-se fazer isso nas Activities que fazem uso do banco de dados, preferen-cialmente no seu método “onCreate()”.

Page 24: Mobile 067 Asqgbnyu

Introdução ao Framework ORM Android JPDroid – Parte 2

24 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 25 24 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 25

Na classe MainActivity.java devemos criar uma variável do tipo Jpdroid, este no escopo da classe, para tratar a persistência de dados. Após isso, no método onCreate(), deve-se parametrizá-lo conforme código da Listagem 4.

Observe a declaração do objeto Jpdroid (linha 02), sendo o mes-mo instanciado na linha 08. Na sequência é informado o contexto para o framework (linha 09), assim como adicionadas as classes de entidade ao framework (linhas 11 a 13) para então chamar o método open() (linha 13) que fará a criação das tabelas.

Agora a Activity já está apta a trabalhar com a persistência de dados. O passo seguinte é mudar a interface da tela principal (activity_mainl.xml), a qual conta com um EditText para pesquisa

por pessoa e um ListView com todos os dados cadastrados. Na parte inferior da tela temos também alguns botões de comando. O código do layout é apresentado na Listagem 5.

A tela pode ser dividida em três partes: topo, centro e rodapé. No topo (linhas 09 a 32) existem dois componentes visuais, um EditText (linha 14) para digitação do nome de uma Pessoa, e o componente ImageButton (linha 24) para realizar a pesquisa pelo parâmetro digitado no campo anterior.

Ao centro temos um componente ListView (linha 34) que apre-sentará o nome de todas as Pessoas cadastradas ou que foram pesquisados pelo ImageButton do topo.

Na parte inferior da tela (linhas 41 a 66) foram adicionados três botões: o primeiro (linha 46) para iniciar o cadastro de um novo contato, o segundo (linha 53) para realizar o backup e o terceiro (linha 60) para restaurar o backup.

A proposta para tela principal do aplicativo é possibilitar a pesquisa dos registros, apresentando na parte central a listagem de pessoas, o que melhora consideravelmente a usabilidade do aplicativo. Deve-se evitar ao máximo o uso de múltiplas telas para tarefas distintas. Sempre que possível, as funcionalidades devem permanecer em apenas um local.

Desta forma, no rodapé temos as opções para adicionar um novo registro, realizar backup e restauração dos dados. O clique longo no componente ListView exibirá um menu suspenso com as opções para edição e exclusão do registro selecionado.

Ao concluir o código, no modo design esta tela fica com aparência próxima à apresentada na Figura 7.

Listagem 3. Pessoa.class

01. @Entity02. public class Pessoa {03. 04. @PrimaryKey05. @Column06. private Long _id;07. 08. @Column09. private String nome;10. 11. @RelationClass(relationType=RelationType.ManyToOne,joinColumn=”idPessoa”)12. private List<Contato> contatos;13. 14. public Long get_id() {15. return _id;16. }17. public void set_id(Long _id) {18. this._id = _id;19. }20. public String getNome() {21. return nome;22. }23. public void setNome(String nome) {24. this.nome = nome;25. }26. public List<Contato> getContatos() {27. return contatos;28. }29. public void setContatos(List<Contato> contatos) {30. this.contatos = contatos;31. }32. }

Listagem 4. Método onCreate

01. public class MainActivity extends Activity {02. private Jpdroid database;03. 04. @override05. protected void onCreate(Bundle savedInstanceState) {06. super.onCreate(savedInstanceState);07. setContentView(R.layout.activity_main);08. database = Jpdroid.getInstance();09. database.setContext(this);10.11. database.addEntity(Pessoa.class);12. database.addEntity(TipoContato.class);13. database.addEntity(TipoContato.class);13. database.open();14. }

Figura 7. Tela principal do aplicativo em modo design

Page 25: Mobile 067 Asqgbnyu

24 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 25 24 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 25

Para complementar a primeira tela, vamos adicionar a ela um menu de contexto que auxiliará na manipulação dos dados. Para isto, este menu será chamado no clique longo do componente ListView. Assim, na pasta res/menu vamos alterar o arquivo activity_main.xml modificando-o conforme a Listagem 6.

Agora vamos à codificação da Activity principal do aplicativo. Seu código é apresentado nas Listagens 7 e 8.

O código desenvolvido possui dois erros de compilação: linhas 57 e 137. Este erro acontece, pois a classe PessoaActivity.java ainda não foi codificada. Desta forma, para o desenvolvimento e compilação do programa estas linhas podem ser comentadas.

A classe MainActivity.java declara os objetos do tipo Jpdroid (instância do objeto que manipulará o banco de dados), um ListView e um EditText (linhas 04 a 06). Estes dois últimos são componentes visuais da tela principal do aplicativo.

No método onCreate() encontra-se a instanciação dos compo-nentes ListView e EditText (linhas 13 e 14), assim como criação e parametrização do framework de manipulação dos dados (linhas 16 a 21).

Para exemplificar o processo de importação inicial dos dados, na linha 23 é verificado se o banco já existe (se não existe, sig-nifica que é a primeira execução). Neste caso, são importados os dados presentes em um script SQL, este armazenado na pasta asset do projeto com nome de import.sql. Seu conteúdo é apresentado a seguir (a linha 24 é responsável pela execução deste script SQL):

01. INSERT INTO TipoContato (_id,descricao) values(1,”E-mail”);

02. INSERT INTO TipoContato (_id,descricao) values(2,”Telefone”);

03. INSERT INTO TipoContato (_id,descricao) values(3,”Celular”);

O passo seguinte é apresentar os dados armazenados da tabela Pessoa no ListView da tela, através da chamado do método adquirirPessoa() – linha 27. Este método foi codificado entre as linhas 37 e 54.

Listagem 5. Layout

01. <LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”02. xmlns:tools=”http://schemas.android.com/tools”03. android:id=”@+id/LinearLayout1”04. android:layout_width=”fill_parent”05. android:layout_height=”fill_parent”06. android:orientation=”vertical”07. tools:context=”com.rafael.androidcomjpdroid.MainActivity” >08. 09. <LinearLayout10. android:layout_width=”match_parent”11. android:layout_height=”44dp”12. android:orientation=”horizontal” >13. 14. <EditText15. android:id=”@+id/etPesquisa”16. android:layout_width=”wrap_content”17. android:layout_height=”wrap_content”18. android:layout_weight=”1”19. android:ems=”10” >20. 21. <requestFocus />22. </EditText>23. 24. <ImageButton25. android:id=”@+id/btPesquisaPessoa “26. android:layout_width=”64dp”27. android:layout_height=”40dp”28. android:layout_weight=”0.42”29. android:background=”@android:color/white”30. android:onClick=”btnPesquisaOnClick”31. android:src=”@android:drawable/ic_menu_search” />32. </LinearLayout>33. 34. <ListView35. android:id=”@+id/lvPessoa”36. android:layout_width=”fill_parent”37. android:layout_height=”wrap_content”38. android:layout_weight=”1” >39. </ListView>40. 41. <LinearLayout42. android:layout_width=”match_parent”43. android:layout_height=”wrap_content”44. android:orientation=”horizontal” >45. 46. <Button47. android:id=”@+id/btnNovoContato”48. android:layout_width=”160dp”49. android:layout_height=”match_parent”50. android:onClick=”btnNovoContatoOnClick”51. android:text=”Adicionar Pessoa” />52. 53. <Button54. android:id=”@+id/btnBackup”55. android:layout_width=”86dp”56. android:layout_height=”match_parent”57. android:onClick=”btnBackupOnClick”58. android:text=”Backup” />59. 60. <Button61. android:id=”@+id/btnRestore”62. android:layout_width=”match_parent”63. android:layout_height=”match_parent”64. android:onClick=”btnRestoreOnClick”65. android:text=”Restore” />66. </LinearLayout>67. 68. </LinearLayout>

Listagem 6. Arquivo activity_main

01. <menu xmlns:android=”http://schemas.android.com/apk/res/android”02. xmlns:tools=”http://schemas.android.com/tools”03. tools:context=”com.rafael.androidcomjpdroid.PessoaActivity” >04.05. <item06. android:id=”@+id/editarPessoa”07. android:title=”Editar”>08. </item>09. 10. <item11. android:id=”@+id/excluirPessoa”12. android:title=”Excluir”>13. </item>14.15. </menu>

Page 26: Mobile 067 Asqgbnyu

Introdução ao Framework ORM Android JPDroid – Parte 2

26 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 27 26 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 27

01. public class MainActivity extends Activity {02. 03. private static final int PESSOA = 1;04. private Jpdroid database;05. private ListView lvPessoa;06. private EditText etPesquisa;07. 08. @Override09. protected void onCreate(Bundle savedInstanceState) {10. super.onCreate(savedInstanceState);11. setContentView(R.layout.activity_main);12. 13. lvPessoa = (ListView) findViewById(R.id.lvPessoa);14. etPesquisa = (EditText) findViewById(R.id.etPesquisa);15. 16. database = Jpdroid.getInstance();17. database.setContext(this);18. database.addEntity(Pessoa.class);19. database.addEntity(Contato.class);20. database.addEntity(TipoContato.class);21. database.open();22. 23. if (database.isCreate()) {24. database.importSqlScript(ScriptPath.Assets, “import.sql”);25. }26. 27. adquirirPessoas(“”);28. 29. registerForContextMenu(lvPessoa);30. 31. }32. 33. public void btnPesquisaOnClick(View v) {34. adquirirPessoas(etPesquisa.getText().toString());35. }36.

37. private void adquirirPessoas(String filtro) {38. String where = “”;39. if (filtro.trim().matches(“^[0-9]*$”) && filtro.trim().length() > 0) {40. where = “_id = “ + filtro;41. } else {42. where = “nome like ‘%” + filtro + “%’”;43. }44. 45. Cursor cursor = database.createQuery(Pessoa.class, where, “ _id asc “);46. 47. SimpleCursorAdapter dataAdapter = new SimpleCursorAdapter(this,48. android.R.layout.simple_list_item_2, cursor, new String[] {49. “_id”, “nome” }, new int[] { android.R.id.text1,50. android.R.id.text2 }, 0);51. 52. lvPessoa.setAdapter(dataAdapter);53. 54. }55. 56. public void btnNovoContatoOnClick(View v) {57. Intent i = new Intent(this, PessoaActivity.class);58. i.putExtra(“posicao”, 0);59. startActivityForResult(i, PESSOA);60. 61. }62. 63. public void btnBackupOnClick(View v) {64. if (database.exportDbScript() > 0) {65. Toast.makeText(this, “Backup Realizado com sucesso!”,66. Toast.LENGTH_SHORT).show();67. } else {68. Toast.makeText(this, “Houve falha ao realizar o backup!”,69. Toast.LENGTH_SHORT).show();70. }71. }

Listagem 7. Activity principal – Parte 1

72. 73. public void btnRestoreOnClick(View v) {74. if (database.importDbScript() > 0) {75. Toast.makeText(this, “Backup Restaurado com sucesso!”,76. Toast.LENGTH_SHORT).show();77. } else {78. Toast.makeText(this, “Houve falha ao restaurar o backup!”,79. Toast.LENGTH_SHORT).show();80. }81. 82. }83. 84. private void deletePessoa(final int posicao) {85. AlertDialog.Builder builder = new AlertDialog.Builder(this);86. builder.setMessage(“Confirma a exclusão?”);87. builder.setPositiveButton(“Sim”, new DialogInterface.OnClickListener() {88. @Override89. public void onClick(DialogInterface dialog, int which) {90. if (database.delete(Pessoa.class,91. (Cursor) lvPessoa.getItemAtPosition(posicao)) <= 0) {92. Toast.makeText(getBaseContext(),93. “A pessoa não pode ser excluída!”,94. Toast.LENGTH_SHORT).show();95. }96. adquirirPessoas(etPesquisa.getText().toString());97. 98. dialog.dismiss();99. }

100. });101. builder.setNegativeButton(“Não”, new DialogInterface.OnClickListener() {102. @Override103. public void onClick(DialogInterface dialog, int which) {104. dialog.dismiss();105. }106. });107.108. builder.show();109.110. }111.112. public void onActivityResult(int requestCode, int resultCode, Intent data) {113. if (requestCode == PESSOA) {114. if (resultCode == Activity.RESULT_OK && data != null) {115. adquirirPessoas(“”);116. }117. }118. }119.120. @Override121. public void onCreateContextMenu(ContextMenu menu, View v,122. ContextMenuInfo menuInfo) {123. super.onCreateContextMenu(menu, v, menuInfo);124. MenuInflater inflater = getMenuInflater();125. inflater.inflate(R.menu.activity_main, menu);126. }127.

Listagem 8. Activity principal – Parte 2

Page 27: Mobile 067 Asqgbnyu

26 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 27 26 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 27

128. @Override129. public boolean onContextItemSelected(MenuItem item) {130. AdapterContextMenuInfo info = (AdapterContextMenuInfo) item131. .getMenuInfo();132. switch (item.getItemId()) {133. case R.id.excluirPessoa:134. deletePessoa(info.position);135. break;136. case R.id.editarPessoa:137. Intent i = new Intent(this, PessoaActivity.class);138. Cursor cursor = (Cursor) lvPessoa.getItemAtPosition(info.position);

139. Long id = cursor.getLong(cursor.getColumnIndex(“_id”));140. i.putExtra(“_id”, id);141. startActivity(i);142. break;143. default:144. return super.onContextItemSelected(item);145. }146. return super.onContextItemSelected(item);147. }148. }

Continuação: Listagem 8. Activity principal – Parte 2

Inicialmente este método verifica o conteúdo passado por parâ-metro pelo método, verificando se o usuário digitou informações numéricos. Em seguida, ele é executado na linha 40 (pesquisa por número) ou na linha 42 (pesquisa por texto) - diferenciando pelos campos _id (long) e nome (String). No caso da execução via método onCreate() – linha 27, o parâmetro é passado como caractere vazio (linha 27), o que faz recuperar todos os registros.

A linha 45 é responsável pela realização da consulta, armaze-nando seu resultado dentro do objeto cursor (linha 45). Este é a base do SimpleCursorAdapter (linha 47), que é responsável pela apresentação dos dados no ListView (linha 52).

Por fim, ao final do método onCreate(), é executado o registro de um menu de contexto (linha 29) para o ListView. Este é cha-mado quando se tem um clique longo sobre o componente. Este registro executa o método onCreateContextMenu() – linha 121, o qual adiciona os menu de contextos presentes no arquivo R.menu.activity_main. O tratamento deste menu é realizado no método onContextItemSelected() – linha 129, onde é recuperado o evento e verificado se o menu excluirPessoa (linha 133) ou editarPessoa (linha 136) foi selecionado.

O método deletePessoa() da linha 84 apresenta para o usuário uma tela de Alerta definida a partir da linha 85. É definida a mensagem da tela (linha 86) assim com o tratamento caso seja selecionada a opção “Sim” (linhas 87 a 100). Neste caso, é verificado se o registro foi excluído com sucesso (linha 90), caso contrário, uma mensagem informativa é apresentada (linhas 92 a 94). Após isso, a lista com as pessoas cadastradas é refeita (linha 96) e a janela informativa é desfeita (linha 98).

Caso a opção de “Não” apagar seja escolhida (linha 101), apenas a caixa de diálogo é desfeita (linha 104). A linha 108 é responsável pela apresentação dos dados.

O método btnNovoContatoOnClick() da linha 56 é responsável por chamar a tela para cadastro de contato. Já as opções de incluir novo contato (tratado da linha 57 a 59) e editar contato existente (tratado da linha 137 a 142) realizam operações similares. Ambas chamam a janela PessoaActivity.class (linhas 57 e 137), sendo estas as linhas com erro de compilação da classe, já que a classe PessoaActivity.java ainda não foi codificada.

A diferença é que o primeiro caso envia para a PessoaActivity o parâmetro “posicao” valendo zero, permitindo a inclusão de um registro novo na próxima tela. A chamada ao método se dá

com o startActivityForResult (linha 59), o que permite fazer um tratamento no retorno, mais especificamente no onActivityResult (linha 112).

Já na opção de editar, o PessoaActivity é chamado passando o parâmetro “_id” com o valor recuperado do ListView. Por fim, também foi codificado nesta tela as opções para realização do backup – método btnBackupOnClick() – linhas 63 a 71, e btnResto-reOnClick() – linhas 73 a 82. Ambos chamam seus respectivos mé-todos – exportDbScript() – linha 64 e importDbScript() – linha 74, verificando se o processo aconteceu como esperado, apresentando após a execução do comando uma mensagem informativa.

Neste ponto o aplicativo já pode ser testado, porém, como a classe MainActivity ainda possui erros de compilação, os métodos que fazem uso do PessoaActivity devem ser comentados. Ao executar pela primeira vez, a interface do aplicativo é apresentada, confor-me Figura 8.

Neste ponto, iremos desenvolver uma nova tela para cadastrar a pessoa. A mesma é formada por um EditText para digitação do nome, um ListView para listar os contatos desta pessoa (telefone, celular e e-mail), e três botões na parte inferior da tela (Adicionar Contato, Salvar e Cancelar), conforme apresentado na Figura 9.

Figura 8. Tela principal do aplicativo

Page 28: Mobile 067 Asqgbnyu

Introdução ao Framework ORM Android JPDroid – Parte 2

28 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 29 28 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 29

Para criar um novo Activity associado a uma tela, deve-se clicar com o botão direito sobre o projeto, escolhendo a opção New ... Other. Na tela apresentada, deve-se escolher a opção Android Activity dentro da categoria Android.

Um wizard para criação do Activity é apresentado. Neste momento, deve-se escolher a opção New Blank Activity, escolhendo o nome Pes-soaActivity para a classe Java e activity_pessoa o arquivo XML.

Ao finalizar, o código da interface gráfica, presente dentro do arqui-vo activity_pessoa.xml pode ser codificada e deve ficar semelhante ao código apresentado na Listagem 9.

Esta tela possui um TextView informativo no topo (linha 09), as-sim como um EditText para digitar o nome de uma pessoa (linha 14). Após a digitação, os contatos desta pessoa são apresentados no ListView declarado no centro da tela (linha 29). Na parte inferior da tela temos três botões: Adicionar contato (linha 42), Salvar (linha 50) e Cancelar (linha 58).

O código Java referente a esta tela é codificado no arquivo Pesso-aActivity.java, e é apresentado nas Listagens 10 a 12. A estrutura desta classe é similar à da MainActivity apresentada anteriormente. A diferença é que esta é iniciada a partir da tela principal, desta forma, é recuperado no método onCreate() – linha 23, o parâmetro recebido da tela anterior. Se este parâmetro chamado _id for maior do que zero (linha 24), significa que deve ser formatada uma tela de alteração, recuperando a pessoa com este código (linha 25) e apresentando as informações na tela.

O tratamento de clique de um elemento na lista é realizado a partir da linha 36. Se o tipo de contato for igual a 2 ou 3, significa que é um número de telefone, assim, automaticamente o aplicativo abrirá a aplicação nativa de ligação passando o número (linhas 41 a 44). Se o contato for de e-mail (linha 45), a aplicação de e-mail padrão será aberta passando o e-mail da pessoa, um assunto e um texto padrão (linhas 46 a 53).

Figura 9. Tela principal do aplicativo (Modo Design)

Listagem 9. Cadastro de Pessoa

01. <LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”02. xmlns:tools=”http://schemas.android.com/tools”03. android:id=”@+id/LinearLayout1”04. android:layout_width=”match_parent”05. android:layout_height=”match_parent”06. android:orientation=”vertical”07. tools:context=”com.rafael.androidcomjpdroid.PessoaActivity” >08. 09. <TextView10. android:layout_width=”wrap_content”11. android:layout_height=”wrap_content”12. android:text=”Nome:” />13. 14. <EditText15. android:id=”@+id/etNome”16. android:layout_width=”match_parent”17. android:layout_height=”wrap_content”18. android:ems=”10” >19. 20. <requestFocus />21. </EditText>22. 23. <LinearLayout24. android:layout_width=”match_parent”25. android:layout_height=”wrap_content”26. android:layout_weight=”0.15”27. android:orientation=”vertical” >28. 29. <ListView30. android:id=”@+id/lvContatos”31. android:layout_width=”match_parent”32. android:layout_height=”wrap_content” >33. </ListView>34. </LinearLayout>35. 36. <LinearLayout37. android:id=”@+id/LinearLayout2”38. android:layout_width=”match_parent”39. android:layout_height=”wrap_content”40. android:orientation=”horizontal” >41. 42. <Button43. android:id=”@+id/btnAdd”44. android:layout_width=”wrap_content”45. android:layout_height=”wrap_content”46. android:layout_weight=”0.23”47. android:onClick=”btnAddOnClick”48. android:text=”Add Contato” />49. 50. <Button51. android:id=”@+id/btnSalvar”52. android:layout_width=”wrap_content”53. android:layout_height=”wrap_content”54. android:layout_gravity=”right|bottom”55. android:onClick=”btnSalvarOnClick”56. android:text=”Salvar” />57. 58. <Button59. android:id=”@+id/btnCancelar”60. android:layout_width=”wrap_content”61. android:layout_height=”wrap_content”62. android:onClick=”btnCancelarOnClick”63. android:text=”Cancelar” />64. </LinearLayout>65. 66. </LinearLayout>

Page 29: Mobile 067 Asqgbnyu

28 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 29 28 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 29

01. public class PessoaActivity extends Activity {02. 03. private static final int ADD_CONTATO = 1;04. private Jpdroid database;05. private ListView lvContatos;06. private EditText etNome;07. private Long _id;08. private Pessoa pessoa;09. private List<Contato> contatos = new ArrayList<Contato>();10. 11. @Override12. protected void onCreate(Bundle savedInstanceState) {13. super.onCreate(savedInstanceState);14. setContentView(R.layout.activity_pessoa);15. 16. database = Jpdroid.getInstance();17. lvContatos = (ListView) findViewById(R.id.lvContatos);18. etNome = (EditText) findViewById(R.id.etNome);19. 20. lvContatos.setOnItemClickListener(evento);21. 22. Intent i = getIntent();23. _id = i.getLongExtra(“_id”, 0);24. if (_id > 0) {25. pessoa = (Pessoa) database.retrieve(Pessoa.class, “_id = “ + _id,26. true).get(0);27. contatos = pessoa.getContatos();28. etNome.setText(pessoa.getNome());29. fillContato();

30. } else {31. pessoa = new Pessoa();32. }33. registerForContextMenu(lvContatos);34. }35. 36. OnItemClickListener evento = new OnItemClickListener() {37. public void onItemClick(AdapterView<?> arg0, View arg1, int position,38. long arg3) {39. Contato con = contatos.get(position);40. if (con.getIdTipoContato() == 2 || con.getIdTipoContato() == 3) {41. String uri = “tel:” + con.getContato().trim();42. Intent intent = new Intent(Intent.ACTION_CALL);43. intent.setData(Uri.parse(uri));44. startActivity(intent);45. } else if (con.getIdTipoContato() == 1) {46. Intent email = new Intent(Intent.ACTION_SEND);47. email.putExtra(Intent.EXTRA_EMAIL,48. new String[] { con.getContato() });49. email.putExtra(Intent.EXTRA_SUBJECT, “Assunto”);50. email.putExtra(Intent.EXTRA_TEXT,51. “Escreva sua mensagem aqui...”);52. email.setType(“message/rfc822”);53. startActivity(Intent.createChooser(email, “Enviar com :”));54. }55. }56. 57. };

Listagem 10. PessoaActivity.class – Parte 1

58. 59. public void btnAddOnClick(View v) {60. Intent i = new Intent(this, ContatoActivity.class);61. i.putExtra(“posicao”, 0);62. startActivityForResult(i, ADD_CONTATO);63. 64. }65. 66. private void fillContato() {67. 68. MatrixCursor matrixCursor = JpdroidConverter.toMatrixCursor(contatos,69. false);70. 71. SimpleCursorAdapter dataAdapter = new SimpleCursorAdapter(this,72. android.R.layout.simple_list_item_2, matrixCursor,73. new String[] { “nomeTipoContato”, “contato” }, new int[] {74. android.R.id.text1, android.R.id.text2 }, 0);75. 76. lvContatos.setAdapter(dataAdapter);77. }78. 79. public void btnCancelarOnClick(View v) {80. Intent it = new Intent();81. setResult(RESULT_CANCELED, it);82. finish();83. }84. 85. private void deleteContato(int position) {86. Contato del = contatos.get(position);87. if (del.get_id() > 0) {88. database.delete(del);89. }90. contatos.remove(position);91. fillContato();92.

93. }94. 95. public void btnSalvarOnClick(View v) {96. 97. try {98. 99. if (etNome.getText() == null100. || etNome.getText().toString().trim().length() == 0) {101. Toast.makeText(this, “Nome não informado!”, Toast.LENGTH_SHORT)102. .show();103. etNome.requestFocus();104. return;105. }106. if (contatos.isEmpty()) {107. Toast.makeText(this, “Favor Cadastrar pelo menos um contato!”,108. Toast.LENGTH_SHORT).show();109. return;110. }111.112. pessoa.setNome(etNome.getText().toString());113. pessoa.setContatos(contatos);114.115. database.persist(pessoa);116.117. Intent it = new Intent();118. it.putExtra(“_id”, _id);119. setResult(RESULT_OK, it);120. finish();121.122. } catch (JpdroidException e) {123.124. e.printStackTrace();125. }126. }

Listagem 11. PessoaActivity.class – Parte 2

Page 30: Mobile 067 Asqgbnyu

Introdução ao Framework ORM Android JPDroid – Parte 2

30 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 31 30 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 31

127.128. public void onActivityResult(int requestCode, int resultCode, Intent data) {129. if (requestCode == ADD_CONTATO) {130. if (resultCode == Activity.RESULT_OK && data != null) {131. Contato novo = (Contato) data.getExtras().getSerializable(132. “contato”);133. if (novo.get_id() == 0) {134. contatos.add(novo);135. } else {136. contatos.set(data.getIntExtra(“posicao”, 0), novo);137. }138. fillContato();139. }140. }141. }142.143. @Override144. public void onCreateContextMenu(ContextMenu menu, View v,145. ContextMenuInfo menuInfo) {146. super.onCreateContextMenu(menu, v, menuInfo);147. MenuInflater inflater = getMenuInflater();148. inflater.inflate(R.menu.activity_pessoa, menu);149. }150.151. @Override152. public boolean onContextItemSelected(MenuItem item) {

153. AdapterContextMenuInfo info = (AdapterContextMenuInfo) item154. .getMenuInfo();155. switch (item.getItemId()) {156. case R.id.excluirContato:157. deleteContato(info.position);158. break;159. case R.id.editarContato:160. Intent it = new Intent(this, ContatoActivity.class);161.162. Bundle bundle = new Bundle();163. bundle.putSerializable(“contato”,164. (Serializable) contatos.get(info.position));165.166. it.putExtras(bundle);167. it.putExtra(“posicao”, info.position);168.169. startActivityForResult(it, ADD_CONTATO);170.171. break;172. default:173. return super.onContextItemSelected(item);174. }175. return super.onContextItemSelected(item);176. }177.178. }

Listagem 12. PessoaActivity.class – Parte 3

Ao clicar no botão novo será apresentada a tela de novo contato (linhas 60 a 62), este codificado na sequência. O botão cancelar retorna para a tela anterior (linhas 80 a 82). Já a opção deleteCon-tato faz a pesquisa do contato da lista dado sua posição e o excluí do banco de dados (linha 88) assim como da lista (linha 90).

A opção de salvar faz uma validação inicial no campo nome (linha 99) apresentando mensagem de erro caso alguma incon-sistência seja detectada. Se nenhum contato for preenchido (linha 106), uma nova mensagem é apresentada ao usuário. Se tudo estiver certo, a instância do objeto pessoa é valorizada (linhas 112 e 113) e o mesmo é salvo no banco (linha 115), retornando então para a tela anterior.

Ao adicionar um novo contato, este não é gravado imediatamen-te na base de dados. O retorno da activity para manutenção do contato é aguardado no evento onActivityResult() (linha 128 da Listagem 12). Quando o retorno for igual à Activity.RESULT_OK (linha 130), o objeto Contato será deserializado (linha 131). Se o objeto não possuir id, este será adicionado à lista de contatos, caso contrário será substituído o item da lista (linha 136).

O menu de contexto, para manipulação dos contatos, será car-regado pelo evento onCreateContextMenu() (linha 144). As ações dos itens do menu são disparadas pelo evento onContextItem-Selected() (linha 152) conforme o identificador do item. Quando este for igual à R.id.excluirContato, o método deleteContato será invocado (linha 157). Sendo igual a R.id.editarContato, o item da lista de contatos selecionado será serializado (linha 163) para ser enviado como parâmetro para a activity de manutenção do contato.

Esta tela também possui um menu de contexto associado ao ListView (linha 33). Assim, na pasta res/menu deve ser alterado

o arquivo activity_pessoa.xml para o conteúdo apresentado na Listagem 13. Para o menu de contexto será utilizada a opção Editar e Excluir.

Agora será codificada a última tela do sistema responsável por cadastrar os contatos da pessoa. O mesmo é formado por um Spinner que permite selecionar o tipo do contato, um EditText para preenchimento do contato, podendo este receber um número caso o contato seja do tipo telefone ou celular e também um e-mail caso o tipo selecionado seja Email. Por último, temos dois botões, Salvar e Cancelar, conforme tela apresentada na Figura 10.

Para a nova tela, um novo Activity deve ser criado clicando com o botão direito sobre o projeto, New – Other – Android Activity na categoria Android. Da mesma forma que a Activity anterior, deve-se seleciona a opção New Blank Activity dando o nome da classe Java ContatoActivity.java e a tela activity_contato.xml.

Listagem 13. Definição do Menu

01. <menu xmlns:android=”http://schemas.android.com/apk/res/android”02. xmlns:tools=”http://schemas.android.com/tools”03. tools:context=”com.rafael.androidcomjpdroid.ContatoActivity” >04. 05. <item06. android:id=”@+id/editarContato”07. android:title=”Editar”>08. </item>09. 10. <item11. android:id=”@+id/excluirContato”12. android:title=”Excluir”>13. </item>14. 15. </menu>

Page 31: Mobile 067 Asqgbnyu

30 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 31 30 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 31

O código completo desta tela é apresentado na Listagem 14.A interface de cadastro de contato se resume a um componente

Spinner para seleção do tipo do contato (linha 19 a 22). Este tipo de contato pode ser um número de telefone, celular ou ainda um e-mail. Para informar o contato é utilizado um EditText (linha 30 a 34). No final da activity temos mais dois botões.

Figura 10. Cadastro de Contato (Modo Design)

O botão btnSalvarContato (linha 44 a 50) e btnCancelarContato (linha 52 a 57). O botão nomeado como btnSalvarContato irá dis-parar o evento btnSalvarContatoOnClick() que por sua vez será codificado na classe ContatoActivity.java para realizar a persis-tência do contato.

O botão nomeado como btnCancelarContato irá disparar o evento btnCancelarContatoOnClick() que, por sua vez, também será codificado na classe ContatoActivity.java para realizar o cancelamento da edição deste contato.

A Listagem 15 apresenta a declaração da Activity (linha 1), assim como as declarações de objetos (linha 03 a 07). No método onCre-ate(), se o parâmetro recebido for à entidade serializada (linha 23), este registro será editado (linhas 26 a 29), caso contrário, uma nova instância da classe Contato será criada (linha 32).

O método btnSalvarContatoOnClick () irá repassar os dados dos componentes visuais para a entidade para que estes dados sejam persistidos (linha 35 a 47). O método btnCancelarContatoOnClick () apenas cancela a edição voltando para tela anterior (linha 48 a 52). Os tipos de contatos serão carregados através do método ad-quirirTipoContato() (linha 36). Um cursor será carregado através do método createQuery() presente no framework JPDroid. Este método aguarda como parâmetro o tipo da entidade, neste caso a busca irá retornar todos os registros da tabela TipoContato (linha 37).

O carregamento do Spinner ocorre através de um SimpleCur-sosAdapter (linha 39). Para facilitar a usabilidade, conforme o tipo de contato, o EditText recebe o InputType correspondente ao contato (linha 71). Por exemplo, quando o contato for igual a Celular, o InputType é um InputType.TYPE_CLASS_PHONE. Esta funcionalidade troca o tipo de teclado, mostrando somente números ou letras.

Page 32: Mobile 067 Asqgbnyu

Introdução ao Framework ORM Android JPDroid – Parte 2

32 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 33 32 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 33

01. public class ContatoActivity extends Activity {02. 03. private Jpdroid database;04. private Contato contato = null;05. private EditText etContato;06. private static Spinner spTipo;07. private int posicao = 0;08. 09. @Override10. protected void onCreate(Bundle savedInstanceState) {11. super.onCreate(savedInstanceState);12. setContentView(R.layout.activity_contato);13. 14. database = Jpdroid.getInstance();15. 16. etContato = (EditText) findViewById(R.id.etContato);17. spTipo = (Spinner) findViewById(R.id.spTipoContato);18. spTipo.setOnItemSelectedListener(evento);19. 20. adquirirTipoContato();21. 22. Intent it = getIntent();23. Serializable param = it.getExtras().getSerializable(“contato”);24. if (param != null) {25. posicao = it.getIntExtra(“posicao”, 0);26. Contato novo = (Contato) param;27. contato = novo;28. etContato.setText(contato.getContato());29. spTipo.setSelection((Long.valueOf(contato.getIdTipoContato()).intValue()-1));30. 31. } else {32. contato = new Contato();33. }

34. }35. 36. private void adquirirTipoContato() {37. Cursor matrixCursor = database.createQuery(TipoContato.class);38. 39. SimpleCursorAdapter dataAdapter = new SimpleCursorAdapter(40. this, android.R.layout.simple_list_item_2, matrixCursor, new 41. String[]{“_id”,”descricao”}, 42. new int[]{android.R.id.text1,android.R.id.text2}, 0);43. 44. spTipo.setAdapter(dataAdapter);45. 46. }47. 48. public void btnSalvarContatoOnClick(final View v) {49. 50. contato.setContato(etContato.getText().toString());51. Cursor selectItem = (Cursor) spTipo.getSelectedItem();52. contato.setIdTipoContato(selectItem.getLong(0));53. contato.setNomeTipoContato(selectItem.getString(1));54. Intent it = new Intent();55. 56. Bundle bundle = new Bundle();57. bundle.putSerializable(“contato”, (Serializable) contato);58. 59. it.putExtras(bundle);60. it.putExtra(“posicao”, posicao);61. 62. setResult(RESULT_OK, it);63. finish();64. }65. 66. public void btnCancelarContatoOnClick(View v){

Listagem 15. MainActivity.class

01. <LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”02. xmlns:tools=”http://schemas.android.com/tools”03. android:id=”@+id/LinearLayout1”04. android:layout_width=”match_parent”05. android:layout_height=”match_parent”06. android:orientation=”vertical”07. android:paddingBottom=”@dimen/activity_vertical_margin”08. android:paddingLeft=”@dimen/activity_horizontal_margin”09. android:paddingRight=”@dimen/activity_horizontal_margin”10. android:paddingTop=”@dimen/activity_vertical_margin”11. tools:context=”com.rafael.androidcomjpdroid.ContatoActivity” >12. 13. <TextView14. android:id=”@+id/tvTipoContato”15. android:layout_width=”wrap_content”16. android:layout_height=”wrap_content”17. android:text=”@string/tipo” />18. 19. <Spinner20. android:id=”@+id/spTipoContato”21. android:layout_width=”match_parent”22. android:layout_height=”wrap_content” />23. 24. <TextView25. android:id=”@+id/tvContato”26. android:layout_width=”wrap_content”27. android:layout_height=”wrap_content”28. android:text=”@string/contato” />29. 30. <EditText

31. android:id=”@+id/etContato”32. android:layout_width=”match_parent”33. android:layout_height=”wrap_content”34. android:ems=”10” >35. 36. <requestFocus />37. </EditText>38. 39. <LinearLayout40. android:layout_width=”match_parent”41. android:layout_height=”wrap_content”42. android:orientation=”horizontal” >43. 44. <Button45. android:id=”@+id/btnSalvarContato”46. android:layout_width=”wrap_content”47. android:layout_height=”wrap_content”48. android:layout_weight=”0.31”49. android:onClick=”btnSalvarContatoOnClick”50. android:text=”Salvar” />51. 52. <Button53. android:id=”@+id/btnCancelarContato”54. android:layout_width=”wrap_content”55. android:layout_height=”wrap_content”56. android:onClick=”btnCancelarContatoOnClick”57. android:text=”Cancelar” />58. </LinearLayout>59. 60. </LinearLayout>

Listagem 14. Cadastro de Contato

Page 33: Mobile 067 Asqgbnyu

32 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 33 32 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 33

O uso do framework de persistência JPDroid permite que tarefas usuais de desenvolvimento como as operações de CRUD, impor-tação e exportação de dados, backup e restore, entre outros sejam facilitadas quando desenvolvemos aplicativos para smartphones Android. Neste artigo conhecemos as principais facilidades disponibilizadas pelo framework. Além da facilidade trazida, o framework também é estável, sendo uma boa alternativa para seus projetos.

Rafael [email protected] em Sistemas de Informação pela Faculdade Unigua-çu – FAESI de São Miguel do Iguaçu – PR. Especialista em Desenvolvimento de Sistemas para Internet e Dispositivos Móveis pela Universidade Federal do Paraná de Francisco Beltrão - PR. Atua como

desenvolvedor java.

autor

[email protected] em Engenharia Elétrica e Informática Industrial pela Universidade Tecnológica Federaldo Paraná, onde ministra aulas sobre tecnologia Java, Computação Móvel e Sistemas Distribuídos. Escreve artigos para as revistas JavaMagazine e WebMobile Magazine,

onde também elabora vídeo aulas semanais sobre JavaME, foi palestrante de eventos como JavaOne, M3DDLA, FISL, WebMobile TechWeek, Webdays e no Just Java. Evangelista da tecnologia, procura ministrar palestras e minicursos em universidades e eventos.

autor

Dê seu voto em www.devmedia.com.br/webmobile/feedback

Ajude-nos a manter a qualidade da revista!

você gostou deste artigo?

links:

Repositório do frameworkhttps://github.com/RafaelCentenaro/jpdroid

Continuação: Listagem 15. MainActivity.class

67. Intent it = new Intent();68. setResult(RESULT_CANCELED, it);69. finish();70. }71. AdapterView.OnItemSelectedListener evento = new AdapterView.OnItemSelectedListener() {72. public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {73. if (spTipo.getSelectedItem().equals(“Celular”)) {74. etContato.setInputType(InputType.TYPE_CLASS_PHONE);75. } else if (spTipo.getSelectedItem().equals(“E-mail”)) {76. etContato.setInputType(InputType.TYPE_TEXT_VARIATION_EMAIL_ ADDRESS);77. }78. }79. 80. public void onNothingSelected(AdapterView<?> adapterView) {81. return;82. }83. };84. }

Page 34: Mobile 067 Asqgbnyu

34 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 35 34 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 35

O React Native é um novo módulo lançado recentemente pelo Face-

book para o desenvolvimento de aplicativos móveis multiplataforma.

Neste artigo, trataremos de explorar as principais features dessa bi-

blioteca através da criação de um aplicativo de busca de restaurantes

focado para a plataforma iOS.

Através disso, você estará apto a entender como o React se comunica

com os dispositivos, o que é o JSX, como implementar controles de

navegação, assim como usar os principais widgets que a tecnologia

disponibiliza e tudo usando somente JavaScript, CSS e HTML5. Ao

final, veremos como conectar o aplicativo diretamente a um serviço

de Web Service com consumo de conteúdo JSON, tal qual temos nos

aplicativos reais.

Fique por dentro

React Native: Construa aplicações multiplata-forma em JavaScriptRecentemente, na última Conferência React reali-

zada no escritório do Facebook em Menlo Park, foi lançada a biblioteca React Native. Ela consti-

tui um novo módulo introduzido à biblioteca principal, a React JavaScript, que fornece suporte ao desenvolvi-mento de aplicações móveis usando JavaScript, CSS e HTML5. Na seção Links deste artigo você encontra as referências para ambos os sites de cada uma.

Por se tratar de uma biblioteca nova, com recursos novos, muita gente se questiona sobre a real utilidade da mesma, e se vale a pena investir em incorporar mais uma tecnologia a seus projetos. Por outro lado, muitos desenvolvedores consideram a biblioteca eficiente e recomendável, principalmente por duas razões:• Com o React Native a sua aplicação, bem como toda a lógica interna a ela, é toda escrita e executada em JavaScript, o que te possibilita ter um UI (User Interface) totalmente nativo. Logo, você não tem de assumir nenhum compromisso tipicamente associado ao UI da HTML5.• O React introduz uma abordagem nova e altamente funcional para a construção de interfaces de usuário: a interface do usuário é simplesmente expressa como uma nova função do estado atual do aplicativo.

À primeira vista, o código e meios de uso do React Native são muito semelhantes à forma como os fazía-mos com o React, com declarações JavaScript relativas às UIs, mas por detrás de tudo as interfaces do mesmo tem suporte em controllers específicos da biblioteca, em vez de em elementos do objeto DOM.

O ponto chave do React Native é que ele pretende trazer principalmente o poder do modelo de progra-mação do React para o desenvolvimento de aplicativos móveis. O maior objetivo dele é implantar o conceito de uma plataforma learn-once run-anywhere (aprenda uma vez e execute em qualquer lugar), isto é, uma vez aprendidos os conceitos do React, os mesmos podem

ser transcritos para qualquer linguagem de programação, tal como funciona com a lógica de programação.

Neste artigo trataremos de expor todas as principais particula-ridades relacionadas ao React Native, através da construção de uma aplicação nativa em iOS para efetuar a busca de restaurantes de uma marca fictícia que criaremos em todo o Brasil (veja na Figura 1 as telas do nosso aplicativo final). O React também lida com a implementação de aplicações para as outras plataformas móveis, como Android, Windows Phone, etc., logo, uma vez aprendidos os conceitos relacionados ao mesmo de uma forma geral, você estará apto a migrar seu código para quaisquer outras plataformas.

Apesar de se tratar de criar aplicativos em iOS, a perspectiva de desenvolvimento bem como os códigos usados para desenvolver com o React é bem diferente dos usados na linguagem Objective-C, mas muito próximos da linguagem Swift. Uma vez familiarizado com o Swift, por exemplo, você será capaz de reaproveitar os conceitos da tecnologia e aplicá-los em algoritmos e técnicas que encorajem transformações e imutabilidade. Entretanto, a forma como você constrói sua UI é praticamente igual à que usamos para desenvolver com o Objective-C: ainda será imperativa e baseada no UIKit.

Page 35: Mobile 067 Asqgbnyu

34 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 35 34 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 35

Configuração do ambienteO framework do React Native está dispo-

nível para download também no GitHub. Se tiver conhecimentos sobre o Git, poderá efetuar o download do mesmo via clona-gem do repositório para o seu ambiente, ou você pode simplesmente efetuar o download como um arquivo zip (pela opção disponibilizada no próprio GitHub) e descompactá-lo normalmente no seu workspace. Outrossim, se não estiver in-teressado no código fonte do projeto, você pode também usar a interface de linha de comando CLI para criar o projeto React Native, que é a abordagem que usaremos neste artigo.

O React Native faz uso do Node.js para efetuar os builds de código JavaScript. Se você não o tiver instalado ainda em seu Mac, siga os seguintes passos:1. Abra o seu terminal de comandos e digite o comando: brew install node.2. Aguarde até que ele termine a execução. Se alguma mensagem de erro for impressa, execute o comando em modo super usuá-rio: sudo brew install node.3. Pronto, o seu Node.js está instalado a nível de Sistema Operacional.

Caso você já tenha o Node.js instalado, mas está com uma versão antiga, então execute os seguintes comandos para atu-alizar a versão:

brew update

brew upgrade now

Após isso, também precisaremos confi-gurar o Homebrew no seu Mac (se você também não o tiver ainda). O Homebrew é um gerenciador de pacotes para o OS X que incorpora funcionalidades não fornecidas por padrão pelo SO do Mac, como a insta-lação de pacotes nos próprios diretórios, criação de links simbólicos dos arquivos, além de ser totalmente baseado em Git e Ruby. Para isso, usaremos o terminal de linha de comandos do seu Mac que efetu-ará os downloads necessários. Execute o seguinte comando no seu terminal:

ruby -e “$(curl -fsSL https://raw.githubusercontent.com/

Homebrew/install/master/install)”

Este script irá solicitar a instalação dos pacotes de dependência do Homebrew. Após executá-lo, você verá uma resposta semelhante à ilustrada pela Figura 2.

Veja que o comando lista as pastas que o Mac irá instalar na sua máquina, mas antes disso ele pede permissão para que você autorize. Basta pressionar a tecla “return” e o processo de instalação será continuado até o fim. Você saberá que o Homebrew foi instalado com sucesso após receber a mensagem exibida pela Figura 3.

Perceba também que ao final de todo o processo, o terminal ainda exibe as próximas opções que você pode tomar, como selecionar o comando brew help para analisar quais comandos estão à disposição do usuário. Fique à vontade para explorá-los.

Agora só precisamos instalar (ou verifi-car se já o estão) três coisas: • O Node.js;• O Watchman, que representa um serviço observador (watcher) de arquivos do Face-book. Ele basicamente observa eventuais mudanças em arquivos e o avisa quando elas ocorrerem. Ele também é capaz de executar ações pré-programadas quando

alguma mudança se encaixar no teste codificado. No nosso caso, usaremos o Wa-tchman para validar quando o nosso código mudar e, então, efetuar o rebuild automáti-co no mesmo. Isso funciona mais ou menos como no Xcode que faz o rebuild do código sempre que salvamos um arquivo;• E por fim, o React Native.

Para verificar se o Node.js foi instalado corretamente, basta digitar o seguinte comando no terminal:

node -v

Se a versão for impressa (v0.12.2, no caso de ser a versão mais recente na data de escrita deste artigo), significa que o Node.js está ok. Caso tenhamos a mensagem “-bash: node: command not found” sendo im-pressa, significa que você ainda o precisa instalar. O mesmo vale para os demais produtos. Para efetuar as três instalações, basta executar os seguintes comandos, respectivamente:• brew install node• brew install watchman• npm install -g react-native-cli

Figura 1. Telas finais do aplicativo de busca de restaurantes já pronto

Figura 2. Resultado da execução do comando de instalação do Homebrew

Page 36: Mobile 067 Asqgbnyu

React Native: Construa aplicações multiplataforma em JavaScript

36 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 37 36 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 37

Todas as instalações findarão com as respectivas mensagens do local onde os pacotes foram instalados. Geralmente eles ficam localizados no diretório “/usr/local/Cellar/”.

Note que o último comando faz uso do gerenciador de pacotes do Node.js, o npm. Verifique se o mesmo está ok executando o comando npm –v (que deverá imprimir 2.7.4).

Após isso, teremos a ferramenta CLI ins-talada de maneira global (mais um motivo para precisarmos executar o comando em modo sudo). O próximo passo agora é navegar até o diretório onde você deseja criar o seu projeto e usar a ferramenta

• O diretório iOS contém alguns códigos que serão usados para efetuar o bootstrap da sua aplicação.• E o mais importante, o arquivo Busca-dorRestaurante.xcodeproj contempla o projeto Xcode que usaremos para efetuar toda a implementação principal.

Após isso estaremos aptos a abrir o nosso projeto na IDE do Xcode. Portanto, dê dois cliques no referido arquivo xcodeproj e execute o projeto dentro da ferramenta. Você deverá ver a tela da Figura 5 sendo exibida no emulador do Xcode.

Você também deve ter notado que uma outra tela de terminal abriu sozinha em forma de pop-up, com o conteúdo da Listagem 1. Ela representa nada mais que o packager (empacotador) do React Nati-ve executando sobre o nó do aplicativo. Descobriremos o que ele faz mais à frente. É importante que você não feche nunca essa janela do terminal, apenas a deixe executando no plano de fundo sem se pre-ocupar com ela. Se por acaso você fechá-la sem querer, reexecute o projeto novamente e uma nova será criada.

Figura 3. Resultado final da execução do comando de instalação do Homebrew

Figura 4. Estrutura de pastas e arquivos gerada pelo React Native

Para comandos envolvendo o npm, é sempre interessante

executar no modo de super usuário, uma vez que estamos

fazendo alterações importantes a nível de SO. Se por acaso

você receber alguma tela de erro, adicione a cláusula “sudo”

antes do comando em questão.

Nota CLI para construir o mesmo, através do seguinte comando:

react-native init BuscadorRestaurantes

Isso irá criar um projeto inicial contendo tudo que você precisará para construir e executar códigos usando o React Native na sua aplicação. Aguarde até que o comando termine todas as configurações e você verá dentro da referida pasta uma estrutura de arquivos e diretórios semelhante à da Figura 4. Vejamos alguns detalhes sobre os recursos mais importantes da mesma:• O diretório node_modules contém o framework React Native. Dentro dele você encontrará arquivos de exemplo, as biblio-tecas do framework, bem como arquivos de inicialização.• O arquivo index.ios.js representa o esquele-to da aplicação criado pela ferramenta CLI.• O diretório BuscadorRestauranteTests guardará os arquivos que você precisará para usar como testes. Figura 5. Tela inicial gerada pelo React Native no nosso aplicativo

Page 37: Mobile 067 Asqgbnyu

36 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 37 36 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 37

aloMundo React nativePor se tratar de uma tecnologia nova na comunidade, e para que

você não comece já pondo a mão na massa sem os conceitos introdu-tórios da tecnologia, vamos criar um exemplo básico de AloMundo. Para isso, abra o arquivo index.ios.js do nosso projeto em um editor de texto de sua preferência (é aconselhável usar o Sublime Text, pela facilidade de desenvolver código nele) e delete o conteúdo atual do mesmo, adicionando a seguinte linha de código:

‘use strict’;

Isso irá habilitar o Strict Mode (Modo Restrito) do React, o qual adiciona facilidade aos processos de tratamento de exceções forne-cendo mensagens mais detalhadas, bem como desabilita algumas funcionalidades do JavaScript que não serão necessárias à nossa realidade. Em resumo, o Strict Mode irá otimizar o JavaScript que usaremos. Em seguida, adicione a seguinte linha de código:

var React = require(‘react-native’);

Esta, por sua vez, carrega o módulo react-native e o assimila ao React. O React Native faz uso do mesmo módulo para carregar tecnologias como o Node.js por intermédio da função require(), que é extremamente semelhante à importação e “linkagem” de bibliotecas no Swift. Após isso, precisamos efetuar mais algumas mudanças ao arquivo de código (Listagem 2).

Dentre as mudanças, algumas se destacam, a saber:• Da linha 1 a 7, temos a definição da variável estilos que será responsável por conter um estilo simples de CSS a ser utilizado pelo texto que criaremos na tela. Os atributos CSS que estamos usando se equiparam aos disponibilizados nas páginas web, não havendo diferenças no conceito de classe aqui.• Na linha 10 declaramos uma classe JavaScript, a Buscador-RestauranteApp, que, por sua vez, herda de React.Component, o bloco básico de construção do React UI. Os Componnets contêm propriedades imutáveis (variáveis de estado imutável), além de expor um método para renderização. Como a nossa aplicação é relativamente simples, só necessitamos de um método de rende-rização (render, na linha 11).

Listagem 1. Código gerado pela janela do terminal ao rodar o projeto.

========================================================= | Running packager on port 8081. | Keep this packager running while developing on any JS | projects. Feel free to close this tab and run your own | packager instance if you prefer. | | https://github.com/facebook/react-native | =========================================================

Looking for JS files in /Users/macbookpro/Documents/BuscadorRestaurante/BuscadorRestaurante

React packager ready.

Listagem 2. Finalizando o arquivo de JS do AloMundo React Native.

01 var estilos = React.StyleSheet.create({02 text: {03 color: ‘black’,04 backgroundColor: ‘white’,05 fontSize: 30,06 margin: 8007 }08 });09 10 class BuscadorRestauranteApp extends React.Component {11 render() {12 return React.createElement(React.Text, {style: estilos.text}, “Alô Mundo!”);13 }14 }15 16 React.AppRegistry.registerComponent(‘BuscadorRestaurante’, function() { return BuscadorRestauranteApp });

Figura 6. Tela de AloMundo exibida no emulador

• Finalmente, definimos na linha 16 o AppRegistry, que se en-carrega de prover o componente raiz como ponto de partida da aplicação.

Agora basta salvar o arquivo com o código em questão e reexe-cutar a aplicação. Ou você pode optar pelo atalho Command + R, que irá recarregar o projeto no emulador. O resultado deverá ser semelhante ao da Figura 6.

Page 38: Mobile 067 Asqgbnyu

React Native: Construa aplicações multiplataforma em JavaScript

38 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 39 38 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 39

Esse é o resultado da nossa execução no emulador, renderizan-do uma UI nativa, sem fazer uso de nenhum browser. Para ter certeza do que estamos falando, abra o Xcode, selecione o modo de visão “Debug\View Debugging\Capture View Hierarchy” e você verá que nenhuma instância de UIWebView está sendo usada, somente uma View.

Suporte ao JSXA nossa aplicação atualmente está usando o construtor de React.

createElement para construir o UI. Enquanto o nosso código Ja-vaScript é perfeitamente legível na forma que está, uma UI mais complexa com elementos encadeados poderia rapidamente se tornar uma verdadeira bagunça.

Para resolver isso, vamos modificar o trecho do nosso arquivo index.ios.js, especificamente na linha de return do método ren-der(), para o código a seguir:

return <React.Text style={estilos.text}>Alô Mundo (de novo)!</React.Text>;

Isso é o que chamamos de JSX (ou JavaScript Syntax Extension), uma linguagem para demarcar código JavaScript, semelhante à forma como o fazemos com o XML. Ele mixa a sintaxe HTML diretamente com o código JavaScript, e não é de uso obrigatório (você pode usar objetos simples do JavaScript se quiser), mas usaremos no artigo por melhor se adequar aos requisitos de organização do código.

Salve as alterações no arquivo e retorne ao simulador. Mais um vez execute o atalho Cmd + R e você verá a mensagem “Alô Mundo (de novo)!” aparecer no mesmo.

navegaçãoO React Native disponibiliza um recurso de navegação padrão

baseado em pilhas, que é gerenciado pelo controlador de navega-ção do UIKit. Vejamos como adicionar tal comportamento.

Dentro do index.ios.js, renomeie a classe atual BuscadorRestau-ranteApp para AloMundo. Não se preocupe, o texto continuará sendo exibido, mas agora o componente AloMundo não será mais o principal da tela. Em seguida, adicione a classe contida na Listagem 3 logo depois da AloMundo.

Isso irá construir um controlador de navegação, aplicar um estilo e configurar a rota inicial do componente AloMundo. No mundo de desenvolvimento web, routing (ou roteamento) é uma técnica para definir a estrutura de navegação de uma aplicação, onde as páginas (routers) são mapeadas a URLs. Dentro do mesmo arquivo, não esqueça de adicionar uma nova classe CSS à nossa variável “estilos”:

container: {

flex: 1

}

Agora recarregue a página no simulador e o resultado será igual ao da Figura 7.

Figura 7. Tela de AloMundo com navegação incutida

Página de buscasPara iniciar essa implementação, adicione um novo arquivo

ao projeto chamado PaginaBusca.js e o posicione no mesmo diretório do index.ios.js. Adicione o conteúdo presente na Listagem 4 ao mesmo.

O início da implementação se equipara ao que já fizemos no AloMundo, exceto a sentença de associação que temos no fim. Isso é o que chamamos de “atribuição desestruturada” que nos permite extrair múltiplas propriedades de objetos e atribuí-las a variáveis usando uma simples sentença. Como resultado, podemos referenciar tais propriedades no restante do código diretamente, sem necessidade de usar prefixos como fazíamos antes.

Em seguida, precisamos também adicionar o estilo que a nossa página de buscas terá, tal como fizemos no primeiro exemplo. Para isso, adicione o conteúdo da Listagem 5 ao final do arquivo.

Essas são as propriedades CSS padrão da página. Configurar estilos dessa forma é menos visual do que usar um construtor de interfaces, mas é bem melhor que configurar propriedades da visão uma por uma em um método viewLoad(), por exemplo.

Após isso, vamos configurar o componente de busca de fato, atribuindo o estilo anterior e fazendo uso das propriedades iniciais (Listagem 6).

Listagem 3. Código da classe BuscadorRestauranteApp para navegação.

01 class BuscadorRestauranteApp extends React.Component {02 render() {03 return (04 <React.NavigatorIOS05 style={estilos.container}06 initialRoute={{07 title: ‘Buscador de Restaurantes’,08 component: AloMundo,09 }}/>10 );11 }12 }

Page 39: Mobile 067 Asqgbnyu

38 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 39 38 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 39

linha de código logo após a cláusula de declaração da função require(), no topo do arquivo:

var PaginaBusca = require(‘,/PaginaBusca’);

Além disso, modifique também a chamada à propriedade com-ponent (que aponta para BuscadorRestauranteApp) para apontar para PaginaBusca:

component: PaginaBusca

O código do exemplo AloMundo pode ser removido dos diretórios se desejar. Agora é só salvar todos os arquivos e recarregar a página no emulador e o resultado se parecerá com o da Figura 8.

Figura 8. Tela de Buscas de Restaurantes inicial

Até o momento, estamos lidando somente com propriedades CSS simples que configuram margens, paddings, cores, etc. Entretanto, existe uma recente adição à especificação do CSS, chamada Flexbox, que é muito útil para a construção de layouts de aplicações desse tipo.

O React Native faz uso da biblioteca css-layout, uma im-plementação JavaScript da Flexbox padrão que foi transcrita para as linguagens C (para uso no iOS) e Java (para Android). O Facebook criou essa separação inicialmente com o objetivo de abraçar as múltiplas linguagens que temos para desenvolver tanto para a web, quanto para o mundo móvel.

No nosso aplicativo, o layout padrão assume as características de colunas, comumente chamado de main axis (eixo principal), onde os elementos são empilhados de forma vertical ou ho-rizontal. A posição vertical de cada elemento é determinada através de uma combinação de suas margens, altura e padding. O container também configura a propriedade alignItems com o valor center que determina a posição dos itens filhos no eixo transversal. Nesse caso, tudo findará em um texto alinhado ao centro.

Vejamos agora o que é preciso para adicionar os campos de texto e o botão de pesquisa. Vá ao arquivo PaginaBusca.js novamente e insira o código contido na Listagem 7 ao mesmo, logo após a segunda tag <Text> do método render().

Listagem 4. Código inicial da página de buscas.

01 ‘use strict’;02 03 var React = require(‘react-native’);04 var {05 StyleSheet,06 Text,07 TextInput,08 View,09 TouchableHighlight,10 ActivityIndicatorIOS,11 Image,12 Component13 } = React;

Listagem 5. Código referente ao estilo da página de buscas.

01 var estilos = StyleSheet.create({02 descricao: {03 marginBottom: 18,04 fontSize: 16,05 textAlign: ‘center’,06 color: ‘grey’07 },08 container: {09 padding: 28,10 marginTop: 64,11 alignItems: ‘center’12 }13 });

Listagem 6. Código que cria o componente de buscas de fato.

01 class PaginaBusca extends Component {02 render() {03 return (04 <View style={estilos.container}>05 <Text style={estilos.descricao}>06 Busque por restaurantes da nossa marca!07 </Text>08 <Text style={estilos.descricao}>09 Procure pelo nome, CEP ou perto de você...10 </Text>11 </View>12 );13 }14 }15 16 module.exports = PaginaBusca;

O nosso método render() agora traz uma fiel representação de como deve ser usado o JSX e a estrutura que o mesmo provê. Veja que estamos apenas fazendo uso das mesmas declarações do exemplo AloMundo, porém com um pouco mais de conteúdo representado por meio do componente <Text>. A tag <View>, por sua vez, demarca os limites da visão para a mesma estrutura. Na linha 16 podemos ver a associação com o módulo que o arquivo JS representa por si só, permitindo assim que possamos exportar essa classe para uso em outros arquivos.

Antes de testarmos, ainda precisamos atualizar o routing da aplicação para que possamos direcionar o acesso ao novo arquivo criado. Para isso, abra o arquivo index.ios.js e adicione a seguinte

Page 40: Mobile 067 Asqgbnyu

React Native: Construa aplicações multiplataforma em JavaScript

40 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 41 40 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 41

Esse código será responsável por fornecer a estrutura HTML do campo de texto que receberá o nome do restaurante da pesquisa (linha 2), dos botões de Busca (linha 5) e de Busca Por Local (linha 10). Perceba que estamos incutindo alguns elementos de estilo à página que precisam ainda ser implementados na variável de estilos (Listagem 8).

Observe que o uso da vírgula é obrigatório para separar cada uma das classes CSS, diferentemente do que fazemos com arqui-vos CSS originais. Caso você esqueça, uma mensagem de erro aparecerá na tela mostrando a linha e a causa do mesmo.

Reexecute a aplicação e você verá o resultado exibido pela Figura 9.

Listagem 7. Código que monta a estrutura de campo de texto e botão.

01 <View style={estilos.flowRight}>02 <TextInput03 style={estilos.searchInput}04 placeholder=’Buscar por nome ou CEP’/>05 <TouchableHighlight style={estilos.button}06 underlayColor=’#99d9f4’>07 <Text style={estilos.buttonText}>OK</Text>08 </TouchableHighlight>09 </View>10 <TouchableHighlight style={estilos.button}11 underlayColor=’#99d9f4’>12 <Text style={estilos.buttonText}>Buscar por Local</Text>13 </TouchableHighlight>14 </View>

Listagem 8. Código de adição do estilo aos campos criados.

01 flowRight: {02 flexDirection: ‘row’,03 alignItems: ‘center’,04 alignSelf: ‘stretch’05 },06 buttonText: {07 fontSize: 18,08 color: ‘white’,09 alignSelf: ‘center’10 },11 button: {12 height: 36,13 flex: 1,14 flexDirection: ‘row’,15 backgroundColor: ‘#8cc53e’,16 borderColor: ‘#8cc53e’,17 borderWidth: 1,18 borderRadius: 8,19 marginBottom: 10,20 alignSelf: ‘stretch’,21 justifyContent: ‘center’22 },23 searchInput: {24 height: 36,25 padding: 4,26 marginRight: 5,27 flex: 4,28 fontSize: 18,29 borderWidth: 1,30 borderColor: ‘#8cc53e’,31 borderRadius: 8,32 color: ‘#8cc53e’33 }

Figura 9. Tela de Buscas de Restaurantes com campos de entrada e estilo aplicado

Você deve ter percebido que usamos um atributo CSS um tanto quando diferente nas declarações de estilo, o flex (linhas 13 e 27). Esse atributo serve para configurar dimensões de forma flexível, para que as mesmas se adaptem aos diferentes tamanhos de telas dos dispositivos em que o aplicativo for executado.

Além disso, os botões que criamos não são necessariamente botões, uma vez que não usamos tags específicas para isso. Eles funcionam mais como labels que podem ser clicadas. Isso ocorre em vista da facilidade com que o UIKit disponibiliza os componentes para serem impressos na tela, de forma a otimizar o trabalho principalmente no que se refere à quantidade de ele-mentos e tags diferentes.

adicionando estado aos componentesCada componente do React Native tem seu próprio estado de

objeto, que é usado como armazenamento chave-valor. Antes de qualquer componente ser renderizado, ele precisa antes ter seu estado inicial configurado.

A primeira alteração, portanto, consiste em incluir um construtor antes da função render(). Adicione o código da Listagem 9 antes da mesma.

Agora o nosso componente tem uma variável state com um atributo interno stringPesquisa configurado com o valor inicial de “osasco”. Além disso, precisamos referenciar o local de chamada a esse estado, através da propriedade value do campo de texto, assim garantimos que o objeto estará preenchido com o seu respectivo estado quando a tela iniciar, e o método constructor() nos garante isso.

Em seguida, precisamos configurar também a função ouvinte que observará sempre que houver mudanças no texto do mesmo campo. Veja na Listagem 10 o código que precisamos para im-plementar essa funcionalidade.

Agora, sempre que o conteúdo do campo de texto mudar tere-mos essa função sendo executada e, portanto, a propriedade state sendo atualizada com o novo valor. Se o leitor desejar, poderá colocar algumas linhas de log para debugar o estado de quando o texto mudar.

Page 41: Mobile 067 Asqgbnyu

40 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 41 40 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 41

onPress={this.onSearchPressed.bind(this)}

Essa propriedade se encarregará de efetuar a associação entre o pressionamento do botão e o método que executará o código em questão. Em seguida, adicione os dois métodos definidos na Listagem 12 ao mesmo arquivo.

O método _executarQuery() será responsável por conter toda a lógica de busca do nosso aplicativo. A partir daqui o leitor deci-dirá aonde deseja buscar as informações, seja num Web Services disponibilizado na web que será acessado via API HTTP do Java-Script, seja num arquivo de texto, base de dados do dispositivo, etc. O importante é que agora temos toda a estrutura de busca pronta para receber o código que você quiser. Inicialmente, a única responsabilidade que ele tem até agora é exibir o loading de carregando.

O segundo método, por sua vez, está designado apenas para ve-rificar quando o nosso botão é pressionado. Esse tipo de estrutura é muito semelhante à de componentes GUI que temos no Swing do Java ou no C#, por exemplo.

O leitor pode e deve espalhar trechos de console.log pelo código de modo a conseguir enxergar o que está acontecendo no mesmo, debugá-lo. A partir disso, agora é só salvar novamente os arquivos e recarregar o emulador, clicando no campo OK. Você deverá encontrar algo semelhante à Figura 10.

Listagem 9. Construtor para aplicação de estado aos componentes.

constructor(propriedades) { super(propriedades); this.state = { stringPesquisa: ‘osasco’ };}

// Alterações no campo de texto<TextInput style={estilos.searchInput} value={this.state.stringPesquisa} placeholder=’Buscar por nome ou CEP’/>

Listagem 10. Código do ouvinte de mudança no texto e alteração no campo de input.

onSearchTextChanged(event) { this.setState({ stringPesquisa: event.nativeEvent.text });}

<TextInput style={estilos.searchInput} value={this.state.stringPesquisa} onChange={this.onSearchTextChanged.bind(this)} placeholder=’Buscar por nome ou CEP’/>

Listagem 12. Métodos para lidar com execução da query.

_executarQuery(query) { this.setState({ isCarregando: true });}

onSearchPressed() { var query = this.state.stringPesquisa; this._executarQuery(query);}

Listagem 11. Criando código para lidar com o loading da página.

this.state = { stringPesquisa: ‘osasco’, isCarregando: false};

// Dentro do método render()var carregando = this.state.isCarregando ? ( <ActivityIndicatorIOS hidden=’true’ size=’large’/> ) : ( <View/>);

implementação da pesquisaAgora precisamos manipular de fato o click no botão de “Ok”,

criando uma API de requisições que se encaixe e indicando ao usuário que a query está sendo processada. Então, para início de implementação, adicione um novo atributo à propriedade state e em seguida crie um novo componente para se encarregar de exibir a imagem de carregando, conforme demonstrado na Listagem 11.

Essa nova propriedade salvará o estado do processamento da página, ou seja, sempre que alguma atividade estiver sendo exe-cutada no plano de fundo, esse valor deverá ser setado para true e o componente “carregando” manipulado via código.

Para que ele seja adicionado à página, é preciso que usemos o JSX para definir isso. Para tanto, adicione a seguinte linha de código ao final do último componente TouchableHighlight:

{carregando}

E adicione a seguinte propriedade dentro da tag TouchableHi-ghlight responsável por renderizar o texto “OK”: Figura 10. Tela de Buscas de Restaurantes com o campo de carregando exibido

Page 42: Mobile 067 Asqgbnyu

React Native: Construa aplicações multiplataforma em JavaScript

42 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 43 42 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 43

Também precisamos configurar as ações que serão tomadas pelo aplicativo quando:1. Não encontrarmos nenhum resultado na busca, mostrando, assim, uma mensagem de validação (lembrando que essa não é a única mensagem que o app vai manusear, portanto é interessan-te criar uma estrutura genérica o suficiente para abraçar outras situações).2. Encontrarmos algum resultado, exibindo-o em uma segunda tela com uma listagem preparada para tal.

O primeiro ponto é mais simples de resolver, basta que criemos um novo atributo dentro da variável state para salvar tais mensa-gens. Para isso, siga os passos descritos na Listagem 13.

Lembrando que o segundo componente de texto deve ser adiciona-do após o componente de carregando que implementamos antes.

Esse código representa apenas a estrutura, mas ainda precisamos manipulá-la dinamicamente. Antes disso, vamos implementar agora a página que será responsável por exibir a listagem dos restaurantes. Crie um novo arquivo JavaScript de nome Pagina-Resultado.js e adicione o conteúdo inicial da Listagem 14 a ele.

Este código inicial apenas mapeia as variáveis que usaremos no restante da listagem, que compreendem desde o estilo para a imagem do restaurante, o componente ListView que se encar-regará de efetuar o loop de listagem em si, textos, etc. A mesma estrutura de require() se mantém e deve ser seguida para cada nova página criada.

Agora precisamos criar o componente em si. Para isso adicione ao fim do arquivo o conteúdo da Listagem 15.

Esse componente traz algumas configurações semelhantes às que fizemos antes, mas outras são novidades, a saber:• Na declaração do construtor (linha 3) temos dentro um logging sendo efetuado apenas para conferir o atributo de listagem que

receberemos como parâmetro do construtor. Na linha 6 o leitor pode observar a chamada explícita ao construtor da classe Data-Source, interna à API do React Native. Através dela, conseguimos criar um objeto inteligível o suficiente para guardar os dados da listagem em forma de linhas de uma tabela de uma coluna só. Na linha 8 estamos salvando o valor na variável state que será usado posteriormente para exibição de cada linha em específico. Veja que na linha 9 chamamos a função cloneWithRows() que se encarregará de converter a nossa lista “listings” (que deve ser um array obrigatoriamente) em um objeto do tipo DataSource.• A segunda função, representada na linha 13, se encarrega de retornar as tags decoradas (decoradas, por que usam uma espécie de padrão Decorator para desenhar a resposta final) com os dados iterados da lista convertida. As tags não apresentam novidade, exceto pela tag <Image> exposta na linha 20, que se encarrega de receber a URL da imagem a ser exibida. Perceba que, exceto pelos estilos, todos os componentes têm seus valores extraídos do parâmetro rowData, que representa o objeto atual da iteração.

Listagem 13. Criando estrutura de exibição de mensagens no app.

this.state = { stringPesquisa: ‘brasil’, isCarregando: false, msg: ‘’};

// Depois adicione o componente de texto para exibir as msgs<Text style={estilos.descricao}>{this.state.msg}</Text>

Listagem 14. Criando página de listagem dos resultados.

‘use strict’; var React = require(‘react-native’);var { StyleSheet, Image, View, TouchableHighlight, ListView, Text, Component} = React;

Listagem 15. Componente de exibição dos resultados.

01 class PaginaResultado extends Component {02 03 constructor(propriedades) {04 console.log(propriedades.listings)05 super(propriedades);06 var dados = new ListView.DataSource(07 {rowHasChanged: (r1, r2) => r1.guid !== r2.guid});08 this.state = {09 dados: dados.cloneWithRows(propriedades.listings)10 };11 }12 13 renderRow(rowData, sectionID, rowID) {14 15 return (16 <TouchableHighlight 17 underlayColor=’#dddddd’>18 <View>19 <View style={estilos.rowContainer}>20 <Image style={estilos.thumb} source={{ uri: rowData.img_url }} />21 <View style={estilos.textContainer}>22 <Text style={estilos.price}>{rowData.nome}</Text>23 <Text style={estilos.title} 24 numberOfLines={1}>{rowData.endereco}</Text>25 </View>26 </View>27 <View style={estilos.separator}/>28 </View>29 </TouchableHighlight>30 );31 }32 33 render() {34 return (35 <ListView36 dataSource={this.state.dados}37 renderRow={this.renderRow.bind(this)}/>38 );39 }40 41 }4243 module.exports = PaginaResultado;

Page 43: Mobile 067 Asqgbnyu

42 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 43 42 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 43

• Na linha 33 definimos a função de renderização render(), que simplesmente informa a fonte de dados (dataSource) a ser exibida, bem como a função que se encarregará de imprimir cada uma das linhas, renderRow().• Por fim, na linha 43, temos a exportação da página como módulo, conforme fizemos para a página de buscas.

Essa codificação ainda precisa receber a variável de estilos que está usando. Para isso, adicione o conteúdo da Listagem 16 logo após a declaração var, correspondente ao objeto de estilos da página de resultados.

Antes de efetuarmos os testes, ainda precisamos efetuar mais dois passos. O primeiro consiste em adicionar a seguinte linha ao início do arquivo PaginaBusca.js:

var PaginaResultado = require(‘./PaginaResultado’);

Esse código constitui a referência à próxima página, para que assim tenhamos o componente disponível a nível de código na página de buscas e possamos usá-lo para efetuar o controle de navegação.

Já o segundo passo se refere à criação de todo o código de busca, de fato. Transcreva o código presente na Listagem 17 para a sua função _executarQuery() da página PaginaBusca.js.

Vejamos alguns detalhes da listagem:• Da linha 4 a linha 7 estamos criando uma estrutura em mock para fornecer dados de teste para o nosso aplicativo. Perceba que estamos criando um objeto genérico rests que conterá cada um dos dados de cada restaurante. O preenchimento se dá através da

definição de um nome para cada valor dentro do próprio vetor (nome, endereco, etc.).• Na linha 11 efetuamos um loop simples sobre todos os elementos verificando se o texto recebido como query por parâmetro está contido dentro de algum dos nomes dos restaurantes de exemplo. A função toLowerCase() (linha 13) se faz necessária para que não tenhamos de validar se o usuário digitou algo em maiúsculo ou minúsculo. Se encontrarmos alguma coisa, configuramos a vari-ável achou com o valor true e adicionamos cada um dos itens ao vetor result, caso contrário, nada acontece.• Na linha 19 é onde verificamos se o teste passou e, caso positivo, configuramos o state para parar o loading, assim como setamos a propriedade props com os dados necessários para forçar a navega-ção, passando como parâmetro o array de elementos encontrados (linha 24). Caso negativo, avisamos ao usuário que nenhum dado foi encontrado para o valor informado.

Pronto, agora é só salvar os arquivos e reexecutar a aplicação. Você pode acompanhar os fluxos de quando nenhum dado é encontrado e de quando os dados são exibidos com sucesso nas Figuras 11 e 12, respectivamente.

Listagem 16. Componente de exibição dos resultados.

var estilos = StyleSheet.create({ thumb: { width: 80, height: 80, marginRight: 10 }, textContainer: { flex: 1 }, separator: { height: 1, backgroundColor: ‘#dddddd’ }, price: { fontSize: 20, fontWeight: ‘bold’, color: ‘#8cc53e’ }, title: { fontSize: 20, color: ‘#656565’ }, rowContainer: { flexDirection: ‘row’, padding: 10 }});

Listagem 17. Código de busca dos restaurantes, de fato.

01 _executarQuery(query) {02 this.setState({ isCarregando: true });0304 var rests = new Object();05 rests[0] = {nome: ‘Restaurante Espaço Brasil’, endereco: ‘Rua Teste 1’, img_url: ‘http://media-cdn.tripadvisor.com/media/photo-s/02/db/51/26/ espaco-brasil-itacare.jpg’};06 rests[1] = {nome: ‘Restaurante Sabor do Brasil’, endereco: ‘Rua Teste 1’, img_url: ‘http://www.portaldepaulinia.com.br/images/stories/2012/abril/ Sabor-du-Brasil.JPG’};07 rests[2] = {nome: ‘Restaurante Tempero Manero’, endereco: ‘Rua Teste 1’, img_url: ‘http://image.slidesharecdn.com/apresentaofranquia-140918120431 -phpapp01/95/conhea-a-maior-franquia-de-restaurantes-do-brasil-1-638.jpg’};0809 var achou = false;10 var result = new Array();11 for (var i = 0; i < 3; i++) {12 var item = rests[i];13 if (item.nome.toLowerCase().indexOf(query.toLowerCase()) > -1) {14 achou = true;15 result.push(item);16 }17 }1819 if (achou) {20 this.setState({ isCarregando: false , msg: ‘’ });21 this.props.navigator.push({22 title: ‘Resultados’,23 component: PaginaResultado,24 passProps: {listings: result}25 });26 } else {27 this.setState({ isCarregando: false , msg: ‘Nenhum dado encontrado’ });28 }29 }

Page 44: Mobile 067 Asqgbnyu

React Native: Construa aplicações multiplataforma em JavaScript

44 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 45 44 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 45

Dados via Web ServiceAté o momento os dados do nosso aplicativo estão fixos no

código, em forma de mock. Para simular uma situação real, em vez de criarmos todo o aparato server side para lidar com um Web Service de verdade, podemos usar o modo raw do Github, isto é, criamos um arquivo com o conteúdo JSON que simularia uma resposta a um serviço e o consumimos no nosso aplicativo.

Para fazer isso, você precisará ter uma conta no Github. Crie um novo repositório e em seguida vá até a opção “Create a new file here”. Dê um novo ao seu arquivo e adicione o conteúdo da Listagem 18 ao mesmo.

Ele representa apenas o código JSON de retorno com os mesmos dados que tínhamos no mock. Após isso, o arquivo será criado e as opções apresentadas na Figura 13 aparecerão. Clique na opção “Raw” e copie a URL para a qual você será redirecionado. Agora precisamos alterar o arquivo do index.ios.js para se adequar às mudanças (Listagem 19).

Vejamos alguns detalhes sobre a implementação:• Na linha 1 adicionamos uma variável global que recebe o valor da URL raw do Github. Cole aqui a URL que você copiou anteriormente.• Na linha 3 instanciamos a função getInitialState() que se encar-regará de resetar a variável rests.

Figura 11. Resultado de quando nenhum dado é encontrado

Figura 12. Resultado dos dados encontrados com sucesso

Figura 13. Opções disponibilizados para arquivo pelo Github

Listagem 18. Código JSON para simular requisição de Web Service.

{rests: [ {nome: ‘Restaurante Espaço Brasil’, endereco: ‘Rua Teste 1’, img_url: ‘http://media-cdn.tripadvisor.com/media/photo-s/02/db/51/26/ espaco-brasil-itacare.jpg’}, {nome: ‘Restaurante Sabor do Brasil’, endereco: ‘Rua Teste 1’, img_url: ‘http://www.portaldepaulinia.com.br/images/stories/2012/abril/ Sabor-du-Brasil.JPG’}, {nome: ‘Restaurante Tempero Manero’, endereco: ‘Rua Teste 1’, img_url: ‘http://image.slidesharecdn.com/apresentaofranquia-140918120431- phpapp01/95/conhea-a-maior-franquia-de-restaurantes-do-brasil-1-638.jpg’}]}

Listagem 19. Código de alteração do arquivo index.ios.js para receber JSON.

01var REQUEST_URL = ‘https://raw.githubusercontent.com/JulioSampaio/ devmedia/master/restaurantes.json’;0203 getInitialState: function() {04 return {05 rests: null,06 };07 },08 09 fetchData: function() {10 fetch(REQUEST_URL)11 .then((response) => response.json())12 .then((responseData) => {13 this.setState({14 rests: responseData.rests,15 });16 })17 .done();18 },1920 _executarQuery(query) {21 this.setState({ isCarregando: true });2223 var achou = false;24 var result = new Array();25 for (var i = 0; i < 3; i++) {26 var item = this.state.rests[i];27 if (item.nome.toLowerCase().indexOf(query.toLowerCase()) > -1) {28 achou = true;29 result.push(item);30 }31 }3233 if (achou) {34 this.setState({ isCarregando: false , msg: ‘’ });35 this.props.navigator.push({36 title: ‘Resultados’,37 component: PaginaResultado,38 passProps: {listings: result}39 });40 } else {41 this.setState({ isCarregando: false , msg: ‘Nenhum dado encontrado’ });42 }43 }

Page 45: Mobile 067 Asqgbnyu

44 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 45 44 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 45

• A função fetchData() da linha 9 se encarregará de efetuar a chamada HTTP à URL em questão e retornar os dados em for-mato JSON. No fim, ela associa o vetor de restaurantes à variável global rests.• Na função _executarQuery (linha 20) a única mudança que pre-cisamos fazer é referenciar a variável global rests na linha 26.

Após isso, basta salvar os arquivos e reexecutar a aplicação. O resultado das telas permanecerá igual com exceção do tempo de carregamento, que será maior em vista do acesso a um recurso na web.

O leitor pode ficar à vontade para inserir quaisquer tipos de dados que deseje e deixar o estilo da sua listagem mais elegante e completo. Da mesma forma, a quantidade e qualidade dos dados podem ser mudadas a bel prazer, uma vez que estamos lidando com elas de forma “mockada”.

Em uma situação de mundo real, tais dados deveriam vir de algum lugar mais confiável, como um Web Service. Se for esse o caso, você pode construir o seu Web Service (que aqui não será mostrado para não fugir ao escopo do artigo) na tecnologia que desejar e o referenciar pela aplicação. É possível até disponibilizá-lo em nível localhost, usando Java, PHP ou Python, por exemplo, para que você possa efetuar todos os testes sem ter de publicar o serviço em uma hospedagem oficial.

Uma vez com tudo configurado, você poderá implementar re-quisições HTTP ao seu serviço e consumir a resposta dos dados que terão praticamente o mesmo modelo JavaScript/JSON que trabalhamos aqui no artigo.

Ademais, o leitor também pode implementar mais casos de uso que envolvam navegação entre telas, como a que fizemos aqui, como uma tela de detalhamento de cada restaurante, por exem-plo. Ao clicar em um dos itens listados, você faria uma consulta ao mesmo serviço e exibiria os detalhes daquele restaurante, como telefone, um mapa Google com as coordenadas, slider de fotos, vídeo, etc. Você também pode configurar a busca por CEP usando os mesmos serviços de mapa que o Google, Bing, etc. disponibilizam.

Enfim, a criatividade é a chave a partir de agora. O mais impor-tante é saber que com a junção entre o React Native e o JavaScript/CSS/afins você terá recursos muito poderosos em mãos que o fará criar aplicativos cada vez melhores. Bons estudos!

Júlio SampaioÉ analista de sistema e entusiasta da área de Tecnologia da Informação. Atualmente é consultor na empresa Visagio, trabalhando em projetos de desenvolvimento de sistemas es-tratégicos, é também instrutor JAVA. Possui conhecimentos e experiência em áreas como Engenharia de Software e Gerenciamento de Projetos,

tem também interesse por tecnologias relacionadas ao front-end web.

autor

links:

Site oficial da biblioteca React JS.http://facebook.github.io/react/

Site oficial da biblioteca React native.https://facebook.github.io/react-native/

Site da Conferência React, ocorrida no Facebook, Ca.http://conf.reactjs.com/

Site de download do node.js.https://nodejs.org/download/

Site da Conferência React, ocorrida no Facebook, Ca.http://conf.reactjs.com/

Dê seu voto em www.devmedia.com.br/webmobile/feedback

Ajude-nos a manter a qualidade da revista!

você gostou deste artigo?

Page 46: Mobile 067 Asqgbnyu

React Native: Construa aplicações multiplataforma em JavaScript

46 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia PB

C

M

Y

CM

MY

CY

CMY

K

Porta80_AnINst.pdf 1 18/09/2011 14:58:37