Você está na página 1de 64

Comeando a Criar Interfaces Grficas com Android

Introduo
O estudo para criar este artigo foi feito em vrias fontes, mas uma chamou a ateno por teu uma seqncia de exemplos muito bem explicados e de fcil entendimento. O texto se chama Understanding User Interface in Android. Neste artigo vamos aprender como criar interfaces grficas (UI) mais bsicas com Android, utilizando o Eclipse como IDE de desenvolvimento. Pretendo criar outros artigos falando sobre componentes mais complexos ou se aprofundando nos apresentados aqui. Para quem est chegando de mundos um pouco mais obscuros em relao UI, como o Java ME, a diferena gritante e impressiona. Com Android temos gerenciadores de layout sofisticados, componentes estilizados com efeitos atrativos graficamente, alm de uma facilidade no desenvolvimento.

Obs: O Java ME ganhou muito poder UI quando ganhou o framework LWUIT, permitindo uso de componentes e gerenciadores de layouts. Mas quem programou com Java ME pr-LWUIT sabe das dificuldades de criar uma tela amigvel com Canvas. Existem algumas plataformas, como a da RIM (responsvel pelos aparelhos BlackBerry) que redefiniu o Java ME para suas necessidades. Nestes aparelhos, tambm possvel criar telas atraentes para o usurio.

O Android oferece dois modos de criar interfaces grficas, uma definindo um arquivo XML que ser carregado no startup da aplicao e a renderizao da tela construda em tempo de execuo. O outro modo atravs da codificao pura. Na maioria dos casos o desenvolvedor usar as duas maneiras, porm, recomenda-se a preferncia pelo uso do XML. Como vimos nos outros publicados por mim no Java Mvel, um aplicativo Android ter uma Activity, que responsvel pela interface

grfico da aplicao. Na verdade, ela pode ser imaginada como uma tela do seu software.

Obs: A Activity utiliza uma pilha, chamada de activity stack, o ndice que estiver no topo da pilha ser a tela exibida para o usurio da aplicao. Para quem programa para BlackBerry OS ver grandes similaridades com a pilha de Screens desta plataforma.

Como dissemos anteriormente, existem dois modos de criao de UI no Android, aqui vamos nos deter principalmente no XML. Ento, veja o exemplo abaixo:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/nome" /> </LinearLayout>

O XML acima representa a interface grfica, contendo um campo de texto em um layout linear, orientado verticalmente. A aplicao deve possuir no mnimo uma classe que herde de Activity e sobrecarregue o mtodo onCreate:
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); }

Perceba que definidos a interface atravs de um arquivo XML, usando o mtodo setContentView. O R representa a classe com as constantes que identificam os recursos da nossa aplicao.

Ao longo deste artigo vamos ver em detalhes o pouco que fizemos at aqui, vamos a luta.

View e ViewGroup
Quando pensamos em interface grfica de um aplicativo Android devemos ter em mente oque significa View e ViewGroup. Ambos representam qualquer componente visual que voc visualizar na tela do aparelho. Como estas classes so de suma importncia para o entendimento do texto no geral, vou parafrasear o site oficial de desenvolvedores Android: A classe View representa o bloco de construo bsico para componentes de interface grfica. Uma View ocupa uma rea retangular na tela e responsvel por desenhar e controlar os eventos. View a classe bsica para widgets, que so usados para criar componenets de UI interativos (botes, caixas de texto, etc.). A subclasse ViewGroup a classe base para layouts, que so containers invisveis que contm Views (ou outros ViewGroups) e definem as propriedades desse layout. Veja a Figura 1 para um melhor entendimento.

Figura 1: Views e Views Group.

Para fazer com que o leitor entenda definitivamente importncia dessas duas classes, veja a Figura 2: Na interface existe um vasto conjunto de widgets, desde botes at caixas de selees. Todos esses componentes esto dentro de um gerenciador de layout, mais precisamente em um LinearLayout.

Figura 2: Exemplo real de Views e Views Group.

Gerenciadores de Layout
Vamos comear a brincadeira com UI no Android com os gerenciadores de layout. Como o prprio nome indica, estas classes orientam o posicionamento dos widgets na tela. Dependendo do layout utilizado, at a altura e largura do componente alterada. Para quem trabalhou com o swing do Java lembra do BorderLayout, FlowLayout, dentre outros. At mesmo no Java ME possvel utilizar gerenciador parecidos com os mencionados anteriormente, atravs do LWUIT. Inicialmente vamos criar uma aplicao Android que alteraremos conforme o gerenciador de layout a ser estudado.

o Criando o projeto
Recapitulando dos nossos artigos anteriores. Siga o caminho file>new->Android Project. Configure as seguintes opes e clique em Ok:

Project Name: LayoutsAndroid. Contents: Create new project in workspace. Target Name: Android 2.1. Application Name: Layouts Android Package Name: com.estudo.android. Create Activity: LayoutsAndroid

Figura 3: Configuraes do projeto inicial.

O Eclipse j cria o projeto e toda a estrutura de pastas e cdigos necessria. Execute este projeto e ver o seguinte:

Figura 3: Projeto inicial emulado.

D uma olhada tambm no arquivo main.xml, que pode ser encontrado no caminho res->layout.
Listagem 1: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /> </LinearLayout>

O nosso exemplo j usa um gerenciador de layout, o LinearLayout, que, por acaso, ser nosso primeiro objeto de estudo.

o LinearLayout
Este gerenciador organiza seus componentes filhos em uma nica coluna ou nica linha, dependendo da orientao que o mesmo tiver. Para ficar mais claro, vamos editar o arquivo main.xml citado anteriormente:
Listagem 2: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <EditText android:id="@+id/EditText01" android:layout_width="180px" android:layout_height="wrap_content" /> <EditText android:id="@+id/EditText02" android:layout_width="180px" android:layout_height="wrap_content" /> <Button android:id="@+id/Button01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Enviar" /> </LinearLayout>

Se executarmos a aplicao agora, veja como fica:

Figura 4: Projeto alinhados verticalmente.

Vamos fazer algumas alteraes no XML para compreender oque ele faz. Na declarao do layout, que sempre deve ser o n raiz do documento, temos o LinearLayout. Definimos para este componente trs propriedades:
android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"

A orientation defina se os componentes se desenrolaro no sentido horizontal ou vertical. Se a tela ter apenas uma linha ou uma coluna, como falado anteriormente. Mudemos essa propriedade para:
android:orientation="horizontal"

O resultado podemos ver abaixo:

Tambm definimos as propriedades de largura (width) e altura (height). Ambos usam fill_parent, que diz o seguinte: use todo o espao disponvel na tela. Vamos mudar novamente o main.xml, mais especificamente as propriedades do LinearLayout.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical"

android:layout_width="100px" android:layout_height="100px">

O resultado :

Perceba que o restante dos componentes foi cortado, por exceder os limites do seu container, o LinearLayout. Na prtica, porm, vai ser raro as vezes em que este gerenciador de layout no vai ocupar todo o espao disponvel na tela. Existem alguns atributos especficos para componentes que fazem todo sentido quando aplicados no LinearLayout. Vamos trabalhar com duas propriedades: android:layout_weight e android:layout_gravity. Reescreva o main.xml:
LISTAGEM 3: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <EditText android:id="@+id/EditText01" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="0.3" /> <EditText android:id="@+id/EditText02" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="0.7" /> <Button android:id="@+id/Button01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Enviar" android:layout_gravity="right" /> </LinearLayout>

Depois de executar veremos o seguinte:

Figura 7: Utilizando gravity e weight.

A propriedade gravity funciona como uma funo de alinhamento em relao ao container, como usamos right no boto, veja que ele se encontra na extremidade direita da tela. O weight repassa para os componentes o espao no utilizado na tela. H, no se preocupem com os componentes, eles sero tratados daqui a pouco. Volte para a figura 4 e perceba que o espao vazio desapareceu, sendo atribudo para as duas caixas de textos que definiram a propriedade weight. Perceba tambm, que a segunda caixa de texto recebeu 70% do espao no utilizado, por isso ficou maior que a primeira caixa. Bem, encerramos por aqui a discusso sobre a LinearLayout. H, no se preocupe com os widgets (componentes). Logo veremos detalhadamente cada um.

o AbsoluteLayout
Este gerenciador define exatamente a posio (coordenada x/y) onde cada componente deve ficar. Este layout menos flexvel e tambm exige um maior trabalho para manuteno. Por exemplo, quando o aparelho muda a orientao, quem deve redefinir a posio dos componentes o programador, via cdigo. Mas chega de conversa, redefina o main.xml para isso:

LISTAGEM 4: <?xml version="1.0" encoding="utf-8"?> <AbsoluteLayout android:layout_width="fill_parent" android:layout_height="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android" > <EditText android:id="@+id/EditText01" android:layout_width="190px" android:layout_height="wrap_content" android:layout_x="12px" android:layout_y="12px" /> <EditText android:id="@+id/EditText02" android:layout_width="190px" android:layout_height="wrap_content" android:layout_x="12px" android:layout_y="60px" /> <Button android:id="@+id/Button01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Enviar" android:layout_x="12px" android:layout_y="161px" /> </AbsoluteLayout>

Quando executamos a nossa aplicao fica com a seguinte cara:

Figura 8: Utilizando AbsoluteLayout.

Simples n? Mas como o leitor j deve ter percebido, na um gerenciador de layout muito aconselhado.

o TableLayout
Este gerenciador pode ser o mais auto-descritivo de todos. Para surpresa geral, ele organiza seus componentes filhos em linhas e colunas. As linhas da tabela so representadas pela classe TableRow. As colunas so criadas conforme a insero de componentes em uma mesma linha. No permitido bordas em linhas, colunas e clulas. Reescreva o main.xml:
LISTAGEM 5: <?xml version="1.0" encoding="utf-8"?> <TableLayout android:layout_width="fill_parent" android:layout_height="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android" > <TableRow> <TextView android:text="Nome" android:layout_width="100px" /> <EditText android:id="@+id/EditText01" android:layout_width="200px" /> </TableRow> <TableRow> <TextView android:text="Endereo"/> <EditText android:id="@+id/EditText02" /> </TableRow> <TableRow> <TextView /> <Button android:id="@+id/Button01" android:text="Enviar" /> </TableRow> </TableLayout>

Para gerar uma interface como a Figura 9:

Figura 8: Utilizando TableLayout.

Vrios pontos devem ser detalhados aqui. Primeiramente, veja que definimos a largura dos componentes somente para a primeira linha. Isso

porque a coluna define sua largura como igual a largura do maior componente horizontal. Assim, se redefinirmos a ltima caixa de texto e o boto para:
<TableRow> <TextView android:text="Endereo"/> <EditText android:id="@+id/EditText02" android:layout_width="100px"/> </TableRow> <TableRow> <TextView /> <Button android:id="@+id/Button01" android:text="Enviar" android:layout_width="50px" /> </TableRow>

O resultado da interface vai ser o mesmo. Tanto o campo de texto de endereo como o boto tem largura menor que a primeira caixa de texto. Na ltima linha colocamos um campo de texto vazio:
<TextView />

Isso deve ser feito para que no ocorra o seguinte efeito:

Figura 8: Utilizando TableLayout com espao a mais.

o RelativeLayout
O RelativeLayout trabalha da seguinte forma. Cada componente filho deve indicar sua posio em relao a outro componente. Vamos comear nossos estudos com este main.xml.

LISTAGEM 6: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout android:id="@+id/RLayout" android:layout_width="fill_parent" android:layout_height="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android" > <TextView android:id="@+id/lblComments" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Idias" android:layout_alignParentTop="true" android:layout_alignParentLeft="true" /> <EditText android:id="@+id/txtComments" android:layout_width="fill_parent" android:layout_height="170px" android:textSize="18sp" android:layout_alignLeft="@+id/lblComments" android:layout_below="@+id/lblComments" android:layout_centerHorizontal="true" /> <Button android:id="@+id/btnSave" android:layout_width="125px" android:layout_height="wrap_content" android:text="Salvar" android:layout_below="@+id/txtComments" android:layout_alignRight="@+id/txtComments" /> <Button android:id="@+id/btnCancel" android:layout_width="124px" android:layout_height="wrap_content" android:text="Lixeira" android:layout_below="@+id/txtComments" android:layout_alignLeft="@+id/txtComments" /> </RelativeLayout>

O primeiro componente, um texto esttico, est orientado em relao ao sei pai, ou seja, ao prprio layout. Ento, definimos que ele estar a esquerda e ao topo da tela.
android:layout_alignParentTop="true" android:layout_alignParentLeft="true"

Antes de prosseguir, veja como fica esta interface em trabalho.

Figura 9: Utilizando RelativeLayout.

A caixa de texto tem sua localizao definida com:


android:layout_alignLeft="@+id/lblComments" android:layout_below="@+id/lblComments"

O layout_alignLeft diz que o componente estar alinhado a esquerda do componente com o id lblCmments, que neste caso, o texto esttico Idias. Tambm, usamos o layout_below para dizer que este componente estar logo abaixo do mesmo componente de texto lblComments. O boto de lixeira define sua localizao com;
android:layout_below="@+id/txtComments" android:layout_alignLeft="@+id/txtComments"

Exatamente da forma como definimos nossa caixa de texto, exceto pela mudana do componente referenciado. Agora indicamos o txtComments como ponto de referncia. Finalmente, temos o boto salvar:
android:layout_below="@+id/txtComments" android:layout_alignRight="@+id/txtComments"

A nica mudana de alignLeft para alignRight.

O desenvolver tem acesso as seguinte propriedades para definir o posicionamento dos componentes no RelativeLayout: * layout_above * layout_alignBaseline * layout_alignBottom * layout_alignLeft * layout_alignParentBottom * layout_alignParentLleft * layout_alignParentRight * layout_alignParentTop * layout_alignRight * layout_alignTop * layout_Below * layout_centerHorizontal * layout_centerInParent * layout_centerVertical * layout_leftOf * layout_rightOf * layout_true

o FrameLayout
O FrameLayout reserva um espao na tela que deve ser utilizado por uma View. Se mais de uma View for colocada nesta rea, haver sobreposio de componentes, com o ltimo que foi inserido aparecendo por primeiro. Vamos a codificao. Altere main.xml:
LISTAGEM 7: <?xml version="1.0" encoding="utf-8"?> <AbsoluteLayout android:id="@+id/AbsoluteLayout01" android:layout_width="fill_parent" android:layout_height="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android"> <FrameLayout android:layout_x="88dip" android:id="@+id/FrameLayout01"

android:layout_height="wrap_content" android:layout_width="wrap_content" android:layout_y="104dip"> <TimePicker android:id="@+id/TimePicker01" android:layout_width="wrap_content" android:layout_height="wrap_content"> </TimePicker> </FrameLayout> </AbsoluteLayout>

Neste XML, apenas o TmePicker pode parecer estranho, mas ele somente um widget para escolher uma hora do dia. Veja visualmente como fica a execuo da aplicao com este XML:

Figura 10: Utilizando FrameLayout.

Estamos usando o FrameLayout dentro de um AbsoluteLayout, logo, devemos especificar sua posio em coordenadas x, y. O FrameLayout possui apenas uma widget, o TimePicker. At aqui parece que no veremos nada de diferente nesse layout. Mas vamos tentar adicionar mais um componente no XML:
<FrameLayout android:layout_x="88dip" android:id="@+id/FrameLayout01" android:layout_height="wrap_content"

android:layout_width="wrap_content" android:layout_y="104dip"> <TimePicker android:id="@+id/TimePicker01" android:layout_width="wrap_content" android:layout_height="wrap_content"> </TimePicker> <Button android:text="Boto" android:id="@+id/Button01" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </FrameLayout>

Agora iniciamos a aplicao e veremos isto:

Perceba que o boto sobreps o TimePicker. Isso acontece porque o FrameLayout mostra apenas uma View.

o ScrollView
Agora fiquei em dvida entre qual dos layout o mais autodescritivo: TableLayout ou ScrollView. Este ltimo, mostra apenas uma ViewGroup que pode exceder os limites da tela fsica do aparelho. Geralmente o ViewGroup utilizado um LinearLayout.

Falta pouco, vamos editar pela ltima vez o main.xml neste tpico de layouts.
<?xml version="1.0" encoding="utf-8"?> <ScrollView android:id="@+id/widget54" android:layout_width="fill_parent" android:layout_height="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android" > <LinearLayout android:layout_width="310px" android:layout_height="wrap_content" android:orientation="vertical" > <Button android:text="Brasil" android:layout_width="110px" android:layout_height="wrap_content" /> <Button android:text="Frana" android:layout_width="110px" android:layout_height="wrap_content" /> <Button android:text="Argentina" android:layout_width="110px" android:layout_height="wrap_content" /> <Button android:text="Uruguai" android:layout_width="110px" android:layout_height="wrap_content" /> <Button android:text="Mxico" android:layout_width="110px" android:layout_height="wrap_content" /> <Button android:text="Paraguai" android:layout_width="110px" android:layout_height="wrap_content" /> <Button android:text="Chile" android:layout_width="110px" android:layout_height="wrap_content" /> <Button android:text="Colmbia" android:layout_width="110px" android:layout_height="wrap_content" /> <Button android:text="Alemanha" android:layout_width="110px" android:layout_height="wrap_content" /> <Button android:text="Estados Unidos" android:layout_width="110px" android:layout_height="wrap_content" /> <Button android:text="Inglaterra" android:layout_width="110px" android:layout_height="wrap_content" /> <Button android:text="Esccia" android:layout_width="110px" android:layout_height="wrap_content" /> </LinearLayout> </ScrollView>

Este layout no tem mistrio, o leitor j deve at estar visualizando mentalmente como ficar a execuo do aplicao desta vez. Veja na Figura abaixo:

Veja a barra no lado direito. Fcil esse scroll view hein.

Views
Depois que aprendemos sobre os gerenciadores de layout, representados pelos ViewsGroups, est na hora de aprender sobre s os componentes, representados pelas classes que herdam de View. Para melhor compreenso, vamos dividir este tpico em cinco reas: Views bsicas: para criar componentes bsicos, como caixa de textos e botes; Pickers Views: componentes especiais que permitem o usurio selecionar de uma certa fonte; Views de listas: componentes que mostram uma lista de informaes; Views para imagens: componentes especializados para tratamento com imagens. Vocs iro se surpreender com estes componentes; Menus; Extras. Antes de iniciarmos este instigante tpico de estudo, vamos criar um novo projeto no Eclipse, chamado ViewsAndroid. Como o leitor j sabe os passos, s vou deixar a imagem com as configuraes:

Agora vamos partir para a ao.

o BasicViews - Incio
As views bsicas no precisam de muita explicao, o leitor j deve ter usado elas intensamente em qualquer software. E, se o leitor for programador, ento j deve ter criado milhares destes componentes:

TextView EditText Button ImageButton CheckBox ToggleButton RadioButton RadioGroup Vamos editar nosso main.xml do projeto recm criado. Reescreva-o com as seguintes informaes:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:id="@+id/txtView" android:text="Cadastro" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <Button android:id="@+id/btnAbrir" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Abrir" /> <ImageButton android:id="@+id/btnImg1" android:layout_width="fill_parent" android:layout_height="wrap_content" android:src="@drawable/icon" /> <EditText android:id="@+id/txtName" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <CheckBox android:id="@+id/chkAutosave" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Autosave" /> <CheckBox android:id="@+id/star" style="?android:attr/starStyle" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <RadioGroup android:id="@+id/rdbSexo"

android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical" > <RadioButton android:id="@+id/rdbM" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Masculino" /> <RadioButton android:id="@+id/F" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Feminino" /> </RadioGroup> <ToggleButton android:id="@+id/toggle1" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>

Rode este projeto e vers o seguinte resultado:

Figura 14: Exemplo de Views.

O primeiro componente um TextView, dispensando maiores apresentaes. O segundo componente um Button, tambm muito auto-

explicativo. O terceiro componente um ImageButton, mesclando uma imagem ao boto tradicional. Aqui podemos perceber um ponto interessante na forma de programar do Android. Sempre devemos definir a fonte da imagem, no nosso exemplo utilizamos:
android:src="@drawable/icon"

O leito deve estar lembrado que na classe Activity usamos a seguinte linha de cdigo:
setContentView(R.layout.main);

Ou seja, ambos referem-se aos recursos localizados na pasta res. A diferena que no primeiro caso acessamos estes recursos atravs do XML, sendo assim devemos definir um @, a localizao do recurso (drawable, layout ou values) e o nome. No ltimo caso acessamos o recurso atravs do cdigo Java. Sendo assim, voc indica a classe R e, o caminho referente ao recurso desejado. Seguindo com o exemplo da Figura 14. O quarto componente um campo de texto, representado pela classe EditView. O quinto componente um simples CheckBox. O sexto componente tambm um CheckBox, mas com uma especificidade. Redefinimos seu estilo, veja:
style="?android:attr/starStyle"

O stimo e oitavo componente so instncias de RadioButton, dentro de um ButtonGroup. Finalmente, o ltimo componente um ToggleButton, um boto estilizado com dois estados: on e off. Tambm podemos mudar os textos do ToggleButton. Adicione mais duas propriedades ao ltimo componente citado:
android:textOn="Sim" android:textOff="No"

Agora o componente apresenta textos definidos pelo programador, e no aqueles padres, veja:

Outro componente que possui atributos importantes para serem citados aqui, o EditText. Em alguns casos, o programador adiciona um campo de texto onde o usurio informa sua senha, sendo assim, o texto deve ser substitudo por asteriscos. Para atingir este objetivo, existe uma propriedade que pode ser adicionada ao EditText:
<EditText android:id="@+id/txtName" android:layout_width="fill_parent" android:layout_height="wrap_content" android:password = "true" />

Veja oque acontece:

o BasicViews Tratamento de Eventos


At agora s mostramos alguns componente na tela, mas no inserimos nenhum tratamento de eventos. E como podemos fazer isso? No incio deste artigo falamos rapidamente que a interface grfica de um aplicativo pode ser construda de duas maneiras: diretamente com o XML ou codificando cada componente. Por exemplo, j usamos o TextView no XML, porm, existe uma classe TextView que pode ser instanciada e tratada diretamente via cdigo.

Mesmo quando optamos por criar a interface via XML, que mais indicada inclusive pelo site de desenvolvedores do Android, vamos usar a codificao pura em Java para tratar dos eventos. Vamos alterar a classe ViewsAndroid, localizada na pasta com.estudo.android, em src:
Listagem 11: 1: package com.estudo.android; 2: 3: import android.app.Activity; 4: import android.os.Bundle; 5: import android.view.View; 6: import android.widget.CheckBox; 7: import android.widget.Toast; 8; 9: public class ViewsAndroid extends Activity { 10: /** Called when the activity is first created. */ 11: @Override 12: public void onCreate(Bundle savedInstanceState) { 13: super.onCreate(savedInstanceState); 14: setContentView(R.layout.main); 15: 16: CheckBox checkBox=(CheckBox) findViewById(R.id.chkAutosave); 17: checkBox.setOnClickListener(new View.OnClickListener() 18: { 19: public void onClick(View v) { 20: Toast.makeText(getBaseContext(), "Salvar "+(((CheckBox)v).isChecked()?"Aut.":"Man."), Toast.LENGTH_SHORT).show(); 21: } 22: }); 23: 24: } 25:}

No sei se vocs perceberam que em todos widgets (componentes) criados at aqui, sempre definimos uma propriedade android:id. Essa identificao usada para recuperar este componente no cdigo Java atravs do mtodo findViewById(), linha 16 da listagem de cdigo 16 . Com posse da instncia de CheckBox podemos configurar um listener para o evento de clique, usando o mtodo setOnClickListener e passando por parmetro uma instncia de OnClickListener. Na Listagem de cdigo isso feito na linha 17. Perceba que instanciamos a classe passada para o mtodo da mesma linha. Quando definimos o mtodo OnClickLisener devemos redefinir o comportamento do mtodo onClick. Este, por sua vez, programa oque acontecer quando o comportamento receber o evento de clique.

Veja nas Figuras abaixo oque programos para o momento em que o boto for selecionado como checado e no-checado. Inicialmente o CheckBox est desativado, ento, quando ele for selecionado mostramos Salvar Aut., caso inverso mostramos Salvar Man..

Figura 15: CheckBox ativado.

Figura 16: CheckBox desativado.

Esse texto que aparece na tela um Toast. Veja a linha de cdigo 20 da Listagem 11. Usamos o mtodo esttico makeToast() que recebe os seguintes parmetros: um contexto, a mensagem e um inteiro que define a durao. No temo usamos a constante LENGHT_SHORT. Para os componentes Button e ToogleButton tambm podemos usar o OnClickListener. Para o RadioButton vamos utilizar o OnCheckedChangeListener. Vamos fazer algumas alteraes no exemplo anterior, assim, o ChangeLisener ser compreendida perfeitamente. A idia associar uma imagem com o campo de escolha do sexo. Sendo assim, a primeira mudana no main.xml, adicionando mais uma propriedade ao boto de escolha do sexo masculino.
<RadioButton android:id="@+id/rdbM" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Masculino" android:checked="true" />

Com isso, a opo de Masculino vai vir marcada como padro. O primeiro passo criar um widget ImageView na nossa tela. Inicialmente ela mostrar uma imagem do sexo masculino:

</RadioGroup> <ImageView android:id="@+id/imgSexo" android:src = "@drawable/menino" android:layout_width="wrap_content" android:layout_height="wrap_content" />

Ao rodar este aplicativo veremos o seguinte:

Figura 17: RadioButton masculino selecionado.

As imagens que aparecero so da internet, voc por qualquer imagem na sua pasta res/drawable e chama-las de menino e menina. Se o usurio escolher Feminino ainda no acontece nada. Eu disse ainda, porque vamos mudar isso agora. Veja a Listagem de cdigo 12:
Listagem 12: 1:public void onCreate(Bundle savedInstanceState) { 2: ... 3: RadioGroup radioGroup = (RadioGroup) findViewById(R.id.rdbSexo); 4: radioGroup.setOnCheckedChangeListener(new OnCheckedChangeListener() 5: { 6: public void onCheckedChanged(RadioGroup group, int checkedId) { 7: RadioButton rdb = (RadioButton) findViewById(checkedId); 8: ImageView img = (ImageView) findViewById(R.id.imgSexo); 9: if (rdb.getText().equals("Feminino")){ 10: img.setImageResource(R.drawable.menina); 11: } else { 12: img.setImageResource(R.drawable.menino); 13: } 14: } 15: }); 16:}

Na linha 4 adicionamos o OnCheckedChangeListener ao componente RadioGroup. Assim, quando um dos RadioButtons for selecionado o mtodo onCheckedChanged(), na linha 6, ser notificado. Os

parmetros que este mtodo recebe so: o RadioGroup que recebeu a iterao e o identificador nico do RadioButton que foi marcado como checado. Na linha 7 recuperamos o objeto RadioButton atravs do id recebido como parmetro. Na linha 8 recuperamos o objeto ImageView da forma j conhecida, ou seja, referenciando o componente atravs das constantes da classe R. Na linha 9 testamos se o texto do RadioButton selecionado igual a Feminino. Caso afirmativo, devemos configurar a fonte do ImageView para a imagem da menininha. E isso que fizemos na linha 11. Caso o teste booleano resulte em false, a imagem mostrada deve ser do menino (como j foi mostrado na Figura 17). Agora podemos executar o aplicativo novamente e marcar a caixa de seleo Feminino. Veremos algo semelhante ao mostrado na Figura 18:

Figura 18: RadioButton masculino selecionado.

o BasicViews Barra de Progresso


A barra de progresso um componente muito comum em qualquer interface de usurio. Seus exemplos de uso podem ser: acompanhar quantos bytes foram transmitidos quando envia seu relatrio para seu chefe, acompanhar um processamento um pouco mais pesado e no pensar que a aplicao deu erro e est travada, dentre outros. Vamos criar uma nova tela para vermos o comportamento desse widget. Crie um novo arquivo .xml em res/layout, chamado barradeprogresso.xml. Veja como na Figura 19:

Figura 19: Criando o barradeprogresso.xml.

Edite o barradeprogresso.xml com o cdigo da Listagem 13:


Listagem 13: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <ProgressBar android:id="@+id/progressbar" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <Button android:id="@+id/btnEnviar" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Enviar" /> </LinearLayout>

Mude tambm a classe ViewsAndroid (Listagem 14).


Listagem 14: package com.estudo.android; import android.app.Activity; import android.os.Bundle; public class ViewsAndroid extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.barradeprogresso); } }

Depois de executar o aplicativo temos:

Essa a forma mais bsica da barra de progresso do Android, d uma olhada nas propriedades e ver que no acrescentamos nada de novo ao que j vnhamos utilizando. O modo que estamos usando este componente padrozinado, seu ciclo indeterminado. til para operaes que no temos idia de quando sero finalizadas. No cdigo acima a barra de progresso (que mais parece um crculo de progresso) vai ficar na tela infinitamente. Vamos adicionar o cdigo da Listagem 15 no onCreate:
Listagem 15: 1:progressBar = (ProgressBar) findViewById(R.id.progressbar); 2: 3:new Thread(new Runnable() { 4: public void run() { 5: while (progressStatus < 10) { 6: progressStatus++;// = doSomeWork(); 7: try {

9: Thread.sleep(500); 10: } catch (InterruptedException e) { 11: e.printStackTrace(); 12: } 13: } 14: 15: progressBar.setVisibility(8); 16: } 17:}).start();

A Listagem 15 recupera o objeto PorgressBar logo na primeira linha. Posteriormente, adicionamos uma rotina com cdigo Java puro, que apenas roda uma Thread enquanto a varivel progressStatus for menor que 10. Depois disse ele muda a visibilidade do ProgressBar, para 8. Execute o aplicativo, espere alguns segundos e...

Como assim? Que erro esse? Substitua a linha 15 pelo conjunto de linhas de cdigo abaixo:
handler.post(new Runnable() { public void run() { progressBar.setVisibility(8); } });

O erro aconteceu porque dentro de uma Thread, no possvel lanar outra linha de execuo. O Handler permite que isso acontece trabalhando diretamente com o sistema operacional. Depois da correo voc pode reiniciar a aplicao e esperar alguns segundos que o ProgressBar desaparecer da tela.

Mas ainda ficou uma questo em aberto. Reveja a linha de cdigo:


progressBar.setVisibility(8);

Afinal, oque significa o parmetro 8. O ProgressBar pode ter trs estados possvel, identificados por nmeros inteiros: 0 visvel 4 invisvel 8 finalizado Por exemplo, se mudarmos a linha do setVisibly para:
progressBar.setVisibility(4);

Depois do mesmo intervalo de tempo veramos:

Mas ainda no acabamos a discusso sobre o ProgressBar. Outra propriedade interessante a possibilidade de mudar o estilo do widget. O primeiro passo redefinir o widget em nosso xml:
<ProgressBar android:id="@+id/progressbar" android:layout_width="wrap_content" android:layout_height="wrap_content" style="?android:attr/progressBarStyleHorizontal" android:max="50" />

Fizemos duas coisas. O atributo style define o estilo do componente. O android:max define o valor mximo da barra de progresso (que agora sim ter um formato de barra de progresso). Na classe ViewsAndroid redefina o bloco de cdigo dentro do while para:
while (progressStatus < 50) { progressStatus++; handler.post(new Runnable() { public void run() { progressBar.setProgress(progressStatus); } }); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } }

Perceba que implementamos o mtodo setProgress dentro do lao, ou seja, a cada iterao a barra de progresso aumenta sua rea completada. Depois chegar aos 50 (seu valor mximo) ela ainda dever sumir, portanto, o restando do cdigo permanece igual. Execute novamente o aplicativo e recebera:

o BasicViews AutoCompleteTextView
O AutoCompleteTextView filho de TextView, sendo assim, ele traz um campo para insero de texto. Seu diferencial a possibilidade de definir um conjunto de Strings que funcionam como auto complemento do texto que est sendo digitado pelo usurio. Reescreva o barradeprogresso.xml com o cdigo da Listagem 16:
Listagem 16: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <AutoCompleteTextView android:id="@+id/txtEstadios" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout>

At este momento apenas criamos o campo de texto. Se olharmos o aplicativo nesse momento a interface conter apenas uma caixa de exto normal, sem complemento de cdigo nenhum. Agora vamos editar tambm o ViewsAndroid com o texto da Listagem 17:
Listagem 17: package com.estudo.android; import import import import android.app.Activity; android.os.Bundle; android.widget.ArrayAdapter; android.widget.AutoCompleteTextView;

public class ViewsAndroid extends Activity { 1: 2: String[] estadios = { "Soccer City", "Ellis Park", "Moses Mabhida", "Peter Mokaba", "Mbombela Stadium", "Loftus Versfeld", "Royal Bafokeng", "Free State", "Green Point", "Nelson Mandela Bay" }; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.barradeprogresso);

3: 4: 5: 6:

7: ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout. simple_dropdown_item_1line, estadios); 8: AutoCompleteTextView textView = (AutoCompleteTextView) findViewById(R.id.txtEstadios); 9: textView.setThreshold(3); 10: textView.setAdapter(adapter); 11: } 12:}

Vamos examinar o cdigo a partir da linha 8. Neste ponto criamos a instncia de AutoCompleteTextView. Na linha 9 usamos o mtodo setThreshold para definir que depois da terceira letra o complemento j pode trabalhar e, finalmente, na linha 10 adicionamos o ArrayAdapter ao componente, este, definir os textos que podem ser usados no complemento. O ArrayAdapter, por sua vez, criado na linha 7. O construtor usado recebe um contexto, que pode ser this. Recebe tambm um segundo parmetro inteiro, que define seu comportamento. O ltimo parmetro recebe um vetor de Objects com as Strings para complemento. Agora podemos executar a aplicao novamente.

Perceba que depois que digito a terceira letra, o e,ele me traz as opes cadastradas no ArrayAdapter.

o PickerViews
Estetipo de widget permite que o usurio selecione uma data ou hora de um componente estilizado e atraente visualmente. Vamos criar uma nova interface que pede o nome do usurio, a data e hora do nascimento e calcula quantos dias faltam para tira a carteira de

habilitao, ou, quantos dias faltam para a aposentadoria (pensando em 65 anos). Se o usurio tiver mais que 65 anos, mostramos quantas copas o usurio j assistiu. Crie um novo arquivo XML chamado datahora.xml:
Listagem 18: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <EditText android:id="@+id/txtNome" android:layout_width="200px" android:layout_height="wrap_content" /> <TimePicker android:id="@+id/pckHora" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <DatePicker android:id="@+id/pckData" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <Button android:id="@+id/btnCalcular" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Calcular" /> </LinearLayout>

No XML da Listagem 18 os nicos dois componentes que se destacam por serem novos so o DatePicker e o TimePicker. As propriedades de ambos j so bem conhecidas do leitor. Tambm altere a classe ViewsAndroid usando o cdigo da Listagem 19:
Listagem 19: package com.estudo.android; import java.util.Calendar; import java.util.Date; import import import import import import import import android.app.Activity; android.os.Bundle; android.view.View; android.widget.Button; android.widget.DatePicker; android.widget.EditText; android.widget.TimePicker; android.widget.Toast;

public class ViewsAndroid extends Activity { private static final String CATEGORIA = "data e hora";

/** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.datahora); } }

Ao executarmos este aplicativo veremos:

Figura 26: Aplicativo usando DatePicker e TimePicker.

Nossa aplicao ainda no far nada se clicarmos no boto Calcular. Para conseguir isso vamos adicionar o trecho de cdigo da Listagem 20 depois da linha do setContentView no mtodo onCreate.
1:Button botao = (Button) findViewById(R.id.btnCalcular); 2;botao.setOnClickListener(new View.OnClickListener(){ 3: public void onClick(View v){ 4: TimePicker hora = (TimePicker) findViewById(R.id.pckHora); 5: DatePicker data = (DatePicker) findViewById(R.id.pckData); 6: EditText edtNome = (EditText) findViewById(R.id.txtNome); 7; 8: Calendar calNasc = Calendar.getInstance(); 9: calNasc.set(Calendar.YEAR, data.getYear()); 10: calNasc.set(Calendar.MONTH, data.getMonth()); 11: calNasc.set(Calendar.DAY_OF_MONTH, data.getDayOfMonth()); 12: calNasc.set(Calendar.HOUR_OF_DAY, hora.getCurrentHour()); 13: calNasc.set(Calendar.MINUTE, hora.getCurrentMinute()); 14: 15: Calendar calHoje = Calendar.getInstance(); 16: calHoje.setTime(new Date());

17: 18: int tempo = calHoje.compareTo(calNasc); 19: 20: if (tempo > 0){ 21: calculaData(calNasc, calHoje, edtNome.getText().toString()); 22: } 23: } 24:});

Nas duas primeiras linhas configuramos o listener para o componente Button. Na linha 3 criamos o mtodo que vai responder por todas iteraes. Nas linhas 4, 5 e 6 recuperamos os objetos para o TimePicker, DatePicker e EditText. Na linha 8 criamos a instncia de Calendar que armazena a data de nascimento do usurio. Na seqncia de linhas de 9 at 11, configuro os valores de ano, ms e data do calendrio, utilizando os mtodos da classe DatePicker para recuperar os valores configurados pelo usurio. As linhas 12 e 13 configuram a hora do dia e o minuto do nascimento do usurio, utilizando mtodos da classe TimePicker. Perceba que no tratamos o tempo, apenas inclumos estas linhas de cdigo como aprendizado, porm, pode ficar como um tema de casa para o leitor. Na linha 15 criamos uma nova instncia de Calendar. Na linha 16 configuramos a data atual como valor para o objeto criado na linha anterior. Na linha 18 utilizamos o mtodo compareTo da classe Calendar para pegar um nmero inteiro com a diferena entre as duas datas comparadas. Se o valor for maior que zero (teste realizado na linha 20), significa que o usurio informou uma data do passado, caso contrrio, a lgica do programa no precisa ser concluda porque ningum nasce no futuro, ainda. O leitor deve ter percebido que paramos no mtodo calculaData, onde passamos trs parmetros: data de nascimento do usurio, data atual e nome do usurio. Veja na Listagem 21 o cdigo do mtodo calculaData:
Listagem 21: public void calculaData(Calendar nascimento, Calendar agora, String nome){ int ano = agora.get(Calendar.YEAR); int mes = agora.get(Calendar.MONTH); int dia = agora.get(Calendar.DAY_OF_MONTH); int anoNasc = nascimento.get(Calendar.YEAR); int mesNasc = nascimento.get(Calendar.MONTH); int diaNasc = nascimento.get(Calendar.DAY_OF_MONTH);

int idade = ano - anoNasc; if(mes < mesNasc) { idade--; } else if (mes == mesNasc) { if(dia < diaNasc) { idade--; } } String mensagem = ""; if (idade < 18) mensagem = nome+ ", faltam "+(18 - idade)+" anos para tirar a carteira!"; else if (idade >= 18 && idade < 65) mensagem = "Calma "+nome+", faltam "+(65 - idade)+" anos para voc se aposentar"; else mensagem = nome+ ", o senhor j assistiu "+(idade/4)+" copas"; Toast.makeText(getBaseContext(), mensagem, Toast.LENGTH_SHORT).show(); }

O cdigo da Listagem 21 no tem segredo, apenas cdigo Java. Primeiramente calculamos a idade, conforme esse resultado configuramos a mensagem do aviso. Finalmente, utilizamos o Toast (j discutido nesse texto), para apresentar a mensagem ao usurio. Veja o resultado de um dos casos:

Figura 27: Caso de uso do aplicativo usando DatePicker e TimePicker.

No utilizamos muito o TimePicker, mas o aplicativo j mostrou uma idia do uso deste componente. Assim como os outros widgets do Android, este bem fcil de usa. O programador tambm pode usar os pickers um uma janela de dilogo. Vamos fazer algumas alteraes, primeiro, no datahora.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:id="@+id/txtAlarme" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Alarme no configurado"/> <Button android:id="@+id/btnConfigurar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Configurar" /> </LinearLayout>

Realmente acho que no preciso explicar o XML. A nossa aplicao vai mostrar uma caixa de texto e um boto. O objetivo que ao interagir com o boto, o usurio receba uma caixa de dilogo com um seletor de hora para configurar seu despertador. Vamos alterar o contedo da classe ViewsAndroid. Veja a Listagem 23:
Listagem 23: 1: private static final int TIME_DIALOG_ID = 0; 2: private TextView lblAlarme; 3: 4: /** Called when the activity is first created. */ 5: @Override 6: public void onCreate(Bundle savedInstanceState) { 7: super.onCreate(savedInstanceState); 8: setContentView(R.layout.datahora); 9: lblAlarme = (TextView) findViewById(R.id.txtAlarme); 10: Button btn = (Button) findViewById(R.id.btnConfigurar); 11: btn.setOnClickListener(new View.OnClickListener(){ 12: public void onClick(View v){ 13: showDialog(TIME_DIALOG_ID); 14: } 15: });

16: 17:

18: @Override 19: protected Dialog onCreateDialog(int id) 20: { 21: switch (id) { 22: case TIME_DIALOG_ID: 23: TimePickerDialog td = new TimePickerDialog( 24: this, mTimeSetListener, 12, 00, false); 25: 26: return td; 27: } 28: return null; 29: } 30: 31: private TimePickerDialog.OnTimeSetListener mTimeSetListener = 32: new TimePickerDialog.OnTimeSetListener() 33: { 34: public void onTimeSet(TimePicker view, int hourOfDay, int minuteOfHour) 35: { 36: lblAlarme.setText("Alarme configurado para " + hourOfDay + ":" + minuteOfHour); 37: } 38: };

Na linha 9 recuperamos o objeto TextView, porque vamos editar seu texto posteriormente. Na linha 10 recuperamos o objeto Button. Na linha 11 adicionamos um OnClickListener para o boto recm criado. Quando o usurio clicar neste componente vamos abrir uma caixa de dilogo. Para que o dilogo mostrado no seja o padro do Android, devemos sobrescrever o mtodo onCreateDialog. Tambm por isso, passamos o TIME_DILAOG_ID como parmetro, para termos certeza de interceptar somente nosso dilogo. Com isso, mensagens vindas diretamente do Android continuaro a serem mostradas. Dentro do onCreatDialog verificamos se estamos recebendo a mensagem do nosso prprio cdigo. Caso afirmativo, instanciamos um novo objeto TimePickerDialog (linha 23). Seu construtor recebe um Context, um OnTimeSetListener, uma hora e um minuto inicial e, por fim, um valor booleano dentificando se o componente trabalhar com 24 horas ou, com horas AM e PM. Perceba que o OnTimeSetListener foi criado no mesmo cdigo, na linha 31, devemos obrigatoriamente implementar o mtodo onTimeSet (linha 34). Este ltimo mtodo chamado sempre que a hora configurada no TimePickerDialog. Quando isso acontecer apenas mudamos o texto do TextView. Veja em trs passos a aplicao em funcionamento:

Figura 28: Tela inicial da aplicao.

Figura 29: Dilogo aberto aps clicar no boto.

Figura 30: Depois de clicar em Set mudamos o texto do TetView.

o ListViews
O ListView um componente para mostrar uma grande lista de dados com scroll. Este componente no precisa de muita explicao, porm, tem algumas diferenas significativas com os exemplos que vimos at aqui. Para explorar ao mximo este widget vamos criar uma lista com todos os pases da copa do mundo de 2010. Ao clicarmos em um dos nomes mostramos a posio da seleo no ranking da FIFA. Primeiramente vamos criar um novo XML, listview.xml. Veja seu contedo na Listagem 24:
Listagem 24: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <ListView android:id="@+id/android:list" android:layout_width="fill_parent" android:layout_height="fill_parent" /> </LinearLayout>

Ainda no vimos nenhuma novidade, mas veja como ficar nossa classe ViewsAndroid na Listagem 25:
Listagem 25: 1:public class ViewsAndroid extends ListActivity { 2: 3: String[] paises = { 4: "Africa do Sul", 5: ... 6: "Uruguai" }; 7: 8: int posicoes[] = new int[]{ 9: 90, ..., 18 }; 10: 11: public void onCreate(Bundle savedInstanceState) 12: { 13: super.onCreate(savedInstanceState); 14: setContentView(R.layout.listview); 15: 16: setListAdapter(new ArrayAdapter<String>(this, 17: android.R.layout.simple_list_item_1, paises)); 18: } 19: 20: public void onListItemClick(ListView parent, View v, int position, long id) { 21: Toast.makeText(this, paises[position]+" est na "+posicoes[position]+" posio", Toast.LENGTH_SHORT).show(); 22: } 23:}

A primeira grande diferena j encontramos na linha 1, perceba que no estendemos mais a classe de Activity, mas sim de ListActivity. O interessante deste componente, que ele j utiliza internamente uma ListView. Na linha 3 criamos um vetor de String com todos os nomes dos pases participantes da copa do mundo. Como no iramos colocar os 32 pases a, usamos as reticncias. Na linha 8 a vez de criar o vetor de inteiros com as posies das selees no ranking da FIFA. O ListActivity precisa que a classe configure seu ListAdapter, que pode ser entendido como um adaptador que faz a ponte entre o vetor de itens com a lista propriamente dita. Na Listagem estamos fazendo isso na linha 16. Um de seus construtores (usados na nossa codificao) recebe um Context, um inteiro que define o layout da lista e um vetor com os itens da lista. Finalmente, implementamos o mtodo onListItemChecked para tratar das interaes do usurio com a lista. Com o parmetro position definimos o pas e sua colocao e apresentamos em um Toast. Veja na Figura abaixo o comportamento do aplicativo em execuo:

Figura 31: Lista de pases com interao no item Brasil.

Nossa lista est configurado para escolha nica, padro do componente. Mas poderamos alterar isso, trabalhando com a sua propriedade android:choiceMode, que permite o uso de trs constantes: none, singleChoice e multipleChoice.

o SpinnerViews
Este componente tambm objetiva mostrar uma grande quantidade de dados em uma lista. Porm, ele mostra uma lista no estilo popup, lembrando o ChoiceGroup estilo POPUP NO Java ME. Vamos trabalhar no mesmo exemplo criado acima mas mudando o componente. Para comear, crie um arquivo chamado spinner.xml e edite-o conforme a Listagem 26:
Listagem 26: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <Spinner

android:id="@+id/spinner1" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>

A classe ViewsAndroid tambm sofrer algumas mudanas. A primeira na declarao da classe, que fica assim:
public class ViewsAndroid extends Activity {

No onCreate tambm teremos alteraes. Veja a Listagem 27:


Listagem 27: 1: super.onCreate(savedInstanceState); 2: setContentView(R.layout.spinner); 3: 4: s1 = (Spinner) findViewById(R.id.spinner1); 5: ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, paises); 6: 7: s1.setAdapter(adapter); 8: s1.setOnItemSelectedListener(new OnItemSelectedListener() { 9: public void onItemSelected(AdapterView<?> arg0, 10: View arg1, int arg2, long arg3) { 11: int index = s1.getSelectedItemPosition(); 12: Toast.makeText(getBaseContext(), paises[index]+" ocupa a "+posicoes[index]+" no ranking da FIFA", Toast.LENGTH_SHORT).show(); 13: } 14: 15: public void onNothingSelected(AdapterView<?> arg0) {} 16:});

Na linha 4 recuperamos o objeto Spinner. Este componente tambm trabalha com um adaptador, criado na linha 5, e configurado para o Spinner na linha 7. Na linha 8 adicionamos o OnItemSelectedListener, e implementamos seus dois mtodos obrigatrios. No onItemSelected recuperamos a posio do item selecionado no Spinner (linha 11) e depois mostramos a mesma mensagem mostrada no exemplo anterior. Veja como ficou este aplicativo:

Figura 32: Tela inicial do aplicativo com Spinner.

Figura 33: Spinner mostrando seus itens.

Figura 34: Tela depois de selecionarmos a Argentina no Spinner.

Tambm podemos mudar a forma como a lista mostrada ao usurio. Altere a linha 5 da lista 27 para:

ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_dropdown_item, paises);

Veja o resultado:

Figura 35: Spinner com layout modificado.

o Gallery e ImageView
A partir desse momento vamos ver componente que nos ajudam a apresentar imagens ao usurio. Se o leitor deste texto estava comeando se apaixonar pelo Android, vai pedir a mo dele em casamento ao final deste tpico. Como este tpico difere dos demais, vamos criar um novo aplicativo, chamado ImagesInAndroid:

Figura 36: Criao do projeto ImagesInAndroid.

Crie um arquivo XML chamado passo1.xml. Veja seu contedo na Listagem 28:
Listagem 28: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <Gallery android:id="@+id/gallery1" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout>

Tambm precisamos alterar a classe ImagesInAndroid. Como as mudanas so vrias, vamos por partes. Primeiramente veja o bsico que j aprendemos sobre Android:
package com.estudos.android; import public class ImagesInAndroid extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.passo1); } }

Nenhuma novidade. O passo seguinte separar algumas imagens e joga-las dentro da patas res.drawable. Veja como fica a estrutura de diretrio na Figura 37:

Figura 37: Arquitetura atualizada com as imagens.

Feito isso, cria-se um varivel com um vetor de instncias de Integer. Veja abaixo como fica. Perceba que estamos referenciando a nossa classe de recursos, R.

Integer[] imageIDs = { R.drawable.pic1, R.drawable.pic2, R.drawable.pic3, R.drawable.pic4, R.drawable.pic5, R.drawable.pic6 };

Agora, vamos adicionar um evento de clique nas imagens do Gallery. O cdigo mostrado abaixo est dentro do mtodo onCreate:
Gallery gallery = (Gallery) findViewById(R.id.gallery1); gallery.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView parent, View v, int position, long id) { Toast.makeText(getBaseContext(), "Selecionou" + (position + 1), Toast.LENGTH_SHORT).show(); } });

Nesse cdigo tambm no encontramos nada de novo em relao ao que j vimos at aqui. Agora execute este arquivo e:

Figura 38: Usando Gallery.

Cad as imagens? As imagens no apareceram porque o Gallery tambm precisa de um adaptador, semelhante ao que ocorre com o ListView e o Spinner, vistos a pouco. Esse adaptador precisa ser criado, diferentemente do Spinner por exemplo, que j tem uma implementao da BaseAdapter para ela (SpinnerAdapter), ou do ListView, que possui o ListAdapter. Sendo assim, vamos criar uma classe interna chamada ImageAdapter, veja na Listagem 32 seu cdigo:
Listagem 33: 1:public class ImagesInAndroid extends Activity 2:{ 3:

4: 5: public class ImageAdapter extends BaseAdapter { 6: private Context context; 7: private int itemBackground; 8: 9: public ImageAdapter(Context c) { 10: context = c; 11: } 12: 13: public int getCount() { 14: return imageIDs.length; 15: } 16: 17: public Object getItem(int position) { 18: return position; 19: } 20: 21: public long getItemId(int position) { 22: return position; 23: } 24: 25: public View getView(int position, View convertView, ViewGroup parent) { } 26: } 27:}

Veja que a classe ImageAdapter est dentro de ImagesInAndroid. Ela herda diretamente de BaseAdapter, e, como a linguagem Java ensina, existem alguns mtodos que devem ser implementados ao herdar esta classe, sendo eles: getCount (linha 13): retorna o nmero de componentes. No nosso caso retornamos o nmero de elementos no vetor imageIDs, que contm as imgens que sero mostradas no Gallery. getItem e getItemId (linhas 17 e 21 respectivamente): retornam o objeto e o identificador do elemento em uma determinada posio. getView (linha 25): retorna um objeto que herda de View que ser mostrado em uma determinada posio do Gallery. Vimos que o getView retorna o objeto que ser mostrado na galeria. Aqui estamos trabalhando com ImageView, mas importante sabe que o mtodo pode retornar qualquer classe que herda de View. Por exemplo, poderamos retornar instncias de TextView. Veja como ficaria o mtodo getView:

public View getView(int position, View convertView, ViewGroup parent) { TextView tv = new TextView(context); tv.setWidth(100);

tv.setText("Teste"); return tv; }

E o resultado :

Figura 39: Usando Gallery com TextView.

Claro que este exemplo no tem nenhuma utilidade prtica, mas serve como prova de conceito. Voltando aquilo que realmente importa neste tpico, que Gallery com ImageView, devemos retornar uma instncia desta ltima classe no lugar do TextView no mtodo getView. Vamos editar novamente o mtodo:
public View getView(int position, View convertView, ViewGroup parent) { ImageView imageView = new ImageView(context); imageView.setImageResource(imageIDs[position]); return imageView; }

E o resultado:

Figura 40: Usando Gallery com ImageView.

As imagens ainda esto com o seu tamanho natural, tambm possvel perceber que elas tem um sombreamento mais claro nas extremidades laterais, isso acontece porque o estilo padro do componente. Vamos configurar algumas propriedades do ImageView para melhorar o Gallery. Adicione mais estas duas linhas de cdigo no corpo do getView:
imageView.setScaleType(ImageView.ScaleType.FIT_XY); imageView.setLayoutParams(new Gallery.LayoutParams(150, 120));

Estamos definindo o tamanho do componente na segunda linha e, na primeira, configuramos o tipo de escala. Como resultado, a imagem vai ocupar toda a rea reservada pra ela (150 por 120 pixeis). Veja como fica na Figura 41:

Figura 41: Usando Gallery com ImageView e parmetros de layout.

Para finalizar com toque de ouro, vamos usar um estilo para melhorar a apresentao das fotos.
public View getView(int position, View convertView, ViewGroup parent) { ... ... ... imageView.setBackgroundResource( android.R.drawable.alert_light_frame); return imageView; }

E o resultado disso:

Figura 42: Usando Gallery com ImageView e estilo.

Mas acho que nossa aplicao ainda no est legal, no momento quando clicamos em uma foto apenas mostramos na tela qual imagem foi clicada:

Figura 43: Resultado inicial de interao com imagens.

Mas acho que podemos fazer melhor que isso. Vamos mostrar a imagem selecionada na parte central da tela, em um componente ImageView. Para conseguir nosso objetivo edite o passo1.xml e adicione o seguinte trecho de cdigo logo depois do Gallery.
<ImageView android:id="@+id/image1"

android:layout_width="320px" android:layout_height="250px" />

Tambm altere o tratamento da interao do usurio com o Gallery, veja:


gallery.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView parent, View v, int position, long id) { ImageView imageView = (ImageView) findViewById(R.id.image1); imageView.setImageResource(imageIDs[position]); } });

O resultado est na Figura 44:

Figura 44: Interao com imagens configurando imagens no centro.

Lembram-se que antes usamos o tipo de escala para definir o comportamento da galeria de imagens na parte superior da tela, tambm podemos usar agora na visualizao da imagem. Adicione o seguinte atributo ao ImageView no passo1.xml:

android:scaleType="fitXY" />

Agora a imagem vai preencher toda a regio reservada ao ImageView. Veja na Figura 45:

Figura 45: ImageView escalado para preencher regio central da tela.

o ImageSwitcher
A troca de imagens que implementamos no exemplo anterior com ImageView e Gallery tambm pode ser conseguida com este componente , e com uma vantagem, o ImageSwitcher permite configurar alguns efeitos 3D na troca das imagens. Este exemplo ser construdo encima do anterior. Sendo assim, edite o arquivo passo1.xml conforme a Listagem 39:
Listagem 39: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#ff000000" > <ImageSwitcher android:id="@+id/switcher1" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_alignParentLeft="true"

android:layout_alignParentRight="true" android:layout_alignParentBottom="true" /> <Gallery android:id="@+id/gallery1" android:layout_width="fill_parent" android:layout_height="wrap_content"/> </RelativeLayout>

Tambm preciso alterar a classe ImagesInAndroid. Siga a Listagem 40:


Listagem 40: 1:public class ImagesInAndroid extends Activity implements ViewFactory { 2: private ImageSwitcher imageSwitcher; 3: 4: Integer[] imageIDs = {}; 5: 6: @Override 7; public void onCreate(Bundle savedInstanceState) 8: { 9: super.onCreate(savedInstanceState); 10: setContentView(R.layout.passo1); 11: 12: imageSwitcher = (ImageSwitcher) findViewById(R.id.switcher1); 13: imageSwitcher.setFactory(this); 14: 15: imageSwitcher.setInAnimation( AnimationUtils.loadAnimation( this, android.R.anim.fade_in)); 16: imageSwitcher.setOutAnimation( AnimationUtils.loadAnimation( this, android.R.anim.fade_out)); 27: 18: Gallery gallery = (Gallery) findViewById(R.id.gallery1); 19: ... 20: gallery.setOnItemClickListener(new OnItemClickListener() { 21: public void onItemClick(AdapterView parent, 22: View v, int position, long id) { 23: imageSwitcher.setImageResource(imageIDs[position]); 24: } 25: }); 26: } 27: 28: public class ImageAdapter extends BaseAdapter 29: {} 30: 31: @Override 32: public View makeView() { 33: ImageView imageView = new ImageView(this); 34: imageView.setBackgroundColor(0xFF000000); 35: imageView.setScaleType(ImageView.ScaleType.FIT_XY); 36: imageView.setLayoutParams(new 37: ImageSwitcher.LayoutParams( LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); 38: return imageView; 39: } 40:}

Vamos falar somente das alteraes feitas na classe anterior. Perceba que na linha 12 recuperamos o componente ImageSwitcher. Na linha 13 usamos o mtodo setFactory para definir a fbrica usada para criar as duas imagens que sero usadas para o componente fazer o flip. Este mtodo recebe como parmetro uma classe que implemente a interface ViewFactory, implementada na mesma classe ImagesInAndroid, veja a linha 1. Nas linhas 15 e3 16 configuramos os eventos que a imagem ter no momento de entrada e de sada da tela do usurio. Tambm mudamos a tarefa a realizar quando o usurio clicar em uma das imagens do Gallery. Neste momento indicamos ao ImageSwitcher qual imagem ele deve apresentar na tela, ele prprio trata da renderizao dos efeitos configurados anteriormente. Por fim, v at a linha 32 e veja que implementamos o mtodo makeView, obrigatrio quando implementamos a ViewFactory. Estemtodo criar a nova View que ser adicionada no switcher. Aqui tambm poderamos passar qualquer componente que herde de View, como fizemos com o TextView no exemplo do tpico anterior (Gallery e ImageView). Ao executar a aplicamos veremos:

Figura 46: Uso do ImageSwitcher.

Aparentemente no percebemos nenhuma diferena, a no ser pelo fato da imagem ocupar a tela inteira. Porm, interaja com o Gallery para ver os efeitos do ImageSwitcher.

o GridView
Para finalizar este artigo/tutorial/ vos mostrar o GridView, que, como o prprio nome indica permite que mostramos imagens em uma grade de fotos. O passo1.xml fica da seguinte maneira:
<?xml version="1.0" encoding="utf-8"?> <GridView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/gridview" android:layout_width="fill_parent" android:layout_height="fill_parent" android:numColumns="auto_fit" android:verticalSpacing="10dp" android:horizontalSpacing="10dp" android:columnWidth="90dp" android:stretchMode="columnWidth" android:gravity="center" />

No prprio XML configuramos algumas propriedades que so prprias de qualquer grade, no s Android, como por exemplo: android:layout_width, android:layout_height, android:numColumns, android:verticalSpacing, android:horizontalSpacing, android:columnWidth.

O ImagesInAndroid sofre mudanas, mas o leitor ir tirar de letra este cdigo a esta altura do campeonato. Veja a Listagem de cdigo 42:
Listagem 42: public class ImagesInAndroid extends Activity { //---the images to display--Integer[] imageIDs = { R.drawable.pic1, R.drawable.pic2, R.drawable.pic3, R.drawable.pic4, R.drawable.pic5, R.drawable.pic6 };

@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.passo1); GridView gridView = (GridView) findViewById(R.id.gridview); gridView.setAdapter(new ImageAdapter(this)); gridView.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView parent, View v, int position, long id) { Toast.makeText(getBaseContext(), "pic" + (position + 1) + " selected", Toast.LENGTH_SHORT).show(); } }); } public class ImageAdapter extends BaseAdapter { private Context context; private int itemBackground; public ImageAdapter(Context c) { context = c; } public int getCount() { return imageIDs.length; } public Object getItem(int position) { return position; } public long getItemId(int position) { return position; } public View getView(int position, View convertView, ViewGroup parent) { ImageView imageView; if (convertView == null) { imageView = new ImageView(context); imageView.setLayoutParams(new GridView.LayoutParams(85, 85)); imageView.setScaleType( ImageView.ScaleType.CENTER_CROP); } else { imageView = (ImageView) convertView; } imageView.setImageResource(imageIDs[position]); return imageView; } } }

Execute a aplicao:

Obs: as fotos so uma homenagem a uma pessoa mais que especial na minha vida, minha noiva e futura esposa. Sheila, te amo. Ah, ela liberou o direito de imagem, est tudo certo.

o CONCLUSO
Primeiramente gostaria de agradecer mais uma vez ao autor do texto Understanding User Interface in Android, que foi de onde parti meu estudo em interfaces de usurio com Android. Alm de outras fontes que pesquisei. No texto foi possvel perceber claramente a facilidade que existe na criao das UIs de nossos aplicativos com a mistura entre XML e codificao Java. Os componentes do Android so fceis de usar e muito bonitos, deixando um programador Java ME como eu de queixo cado, principalmente nas View que tratam de imagens. Se o tempo permitir pretendo continuar com a srie de artigos aqui no Java Mvel, comentrios e sugestes so sempre bem vindos.

o SOBRE MIM
Meu nome Ricardo da Silva Ogliari, sou graduado em Cincia da Computao pela Universidade de Passo Fundo. Atualmente tambm estou cursando uma ps-graduao em web, estratgias de inovao e tecnologia, no Senac SP. Trabalho com mobile a 6 anos, escrevo artigos para algumas revistas nacionais especializadas. Sou criador e mantenedor do http://www.mobilidadetudo.com e sou um dos membros do www.javamovel.com. Palestrei em eventos nacionais e internacionais, como o FISL e o JustJava, alm de ter dezenas de artigos meus espalhados pelo mundo da internet.

Você também pode gostar