Nenhum comentário


Android Studio – Parte IV

Fazendo uma retrospectiva sobre nossos artigos de Android, conhecemos o Android Studio, ferramenta gratuita do Google para criar apps. Vimos como criar aplicativos e seus tipos (templates), além de conhecer controles de tela para criar Activitys etc.

Neste artigo, quero mostrar controles mais avançados, como ProgressBar, TabHost (abas para separar controles de tela), SearchView, além do muito usado ListView. Veremos características dos mesmos e como customizar o ListView com imagens.

Criando um novo projeto

Vamos criar um novo projeto para esses novos exemplos, crie um do tipo Master/Detail Flow. Vamos conhecer primeiramente o ProgressBar, que serve para mostrar ao usuário que algum processo esta sendo executado, assim o mesmo não pensa que a aplicação travou.

O ProgressBar pode ser apenas um texto e uma image, girando, como também podemos mostrar o percentual do processamento. Crie um layout no projeto com o nome de "layout_progress.xml". Adicione um Button. Acesse o arquivo ItemDetailFragment.java e vamos codificar o botão no método onCreateView.

Semelhante ao exemplo anterior, onde precisávamos saber qual item do menu foi selecionado, no tipo Master/Detail, temos um ListView com itens e precisamos saber qual o selecionado. Primeiro declare uma variável privada na classe, para podermos acessar o Progressbar no evento click do botão:

private ProgressDialog pBar;

Também declare a variável:

public View rootView = null;

No método onCreateView, vamos usar o seguinte código:

rootView = new View(getActivity());
if (mItem.id == "1"){
   //botão
   Button btn = (Button)rootView.findViewById(R.id.button);
   btn.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
         //ProgressBar
         pBar = new ProgressDialog(v.getContext());
         pBar.setCancelable(true);
         pBar.setMessage("Exemplo de progressBar");
         pBar.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
         pBar.show();
      }
   });
}

return rootView;

Pegamos do mItem, o identificador do item selecionado, para executar o que precisamos. Usamos um ProgressDialog, um janela com um ProgressBar embutido. Atribuímos uma mensagem (use resource para essa mensagem J), um estilo e chamamos o show.

O setCancelable indica se a barra será fechada, se o usuário tocar na tela fora da área do ProgressBar ou usar a tecla voltar. Coloque false, se deseja que ela não seja fechada pelo usuário. Execute a aplicação, acesse o Item 1 e clique no botão. Teremos o ProgressBar (Figura 1)

Figura 1. ProgressBar em execução

Calma lá, ele não fez nada!!! Claro, não codificamos ele para fazer alguma coisa . Precisamos usar um handler para atualizar o progresso da barra. Primeiro, precisamos indicar qual o mínimo e o máximo para a barra:

pBar.setProgress(0);
pBar.setMax(100);

Após o show(), adicione o seguinte código:

new Thread(new Runnable() {
   public void run() {
      while (i < 100) {
      try {
         Thread.sleep(100);
      } catch (InterruptedException e) {
         e.printStackTrace();
      }

      pBarHandler.post(new Runnable() {
         public void run() {
            pBar.setProgress(i++);
         }
      });
   }
   }
}).start();

Lembrando, que o exemplo é para entendimento e fins didáticos. Usamos uma Thread para fazer um loop até 100. Usamos o método sleep para “pausar” e podermos atualizar em tela a barra. pBarHandler esta declarado na classe, assim como o incrementador:

int i = 0;
private Handler progressBarHandler = new Handler();

O Handler serve para atualizarmos o layout da tela, pois usando uma Thread, não podemos mexer em controles de tela. O método que incrementa o valor é o setProgress. Execute novamente e veja a barra em progresso (Figura 2).

 

Figura 2. ProgressBar com contador

Note que ao chegar o final, o dialogo ainda continua aparecendo. Sim, não dizemos para ele fechar quando chegar em 100%. Após o Handler, coloque o seguinte código:

if (i == 100)
  pBar.dismiss();

Pronto, agora, ao terminar o progresso, a janela será fechada. Outro exemplo para ProgressBar, para quando queremos mostrar apenas o processo e não temos ou não queremos mostrar o percentual. Veja o exemplo no código a seguir:

pBar = new ProgressDialog(v.getContext());
pBar.setCancelable(true);
pBar.setIndeterminate(false);
pBar.setMessage("Processando....");
pBar.show();

Nesse exemplo, o dismiss, que fecha o dialogo, deve ser chamado, após o processamento ser realizado. Exemplo comum, é quando acessamos um banco de dados, retornamos dados usando JSON etc. Veja na Figura 3, o layout do progressBar.

 

Figura 3. ProgressBar sem contador

TabHost

Controle muito eficiente se tivermos vários controles em tela e precisamos organiza-los em abas. Vamos criar um layout, que será o nosso controle, chamando o arquivo de “tabhost.xml”. Para cada aba, precisamos de um layout, assim, se tivermos três abas, precisamos de três arquivos XML.

Nesse exemplo, vamos criar duas abas, então, crie dois arquivos de layout. Adicione os controles que desejar, nesses dois layouts. Vamos voltar ao tabhost.xml e adicionar o nosso layout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
   xmlns:android="http://schemas.android.com/apk/res/android"
   android:orientation="vertical"
   android:layout_width="match_parent"
   android:layout_height="match_parent">

   <TabHost
      android:id="@+id/TabHost01"
      android:layout_width="fill_parent"
      android:layout_height="fill_parent">

      <LinearLayout
         android:layout_width="fill_parent"
         android:layout_height="fill_parent"
         android:orientation="vertical" >

         <!-- TabWidget cria as tabs -->

         <TabWidget
            android:id="@android:id/tabs"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content">
         </TabWidget>

         <!-- layouts das tabs -->

         <FrameLayout
            android:id="@android:id/tabcontent"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent" >

            <!-- Aba 1 -->

            <include
               android:id="@+id/aba1"
               android:layout_width="fill_parent"
               android:layout_height="match_parent"
               layout="@layout/aba_um" >
            </include>

            <!-- Aba 2 -->

            <include
               android:id="@+id/aba2"
               android:layout_width="fill_parent"
               android:layout_height="wrap_content"
               layout="@layout/aba_dois" >
            </include>

            </FrameLayout>
        </LinearLayout>
    </TabHost>
</LinearLayout>

Todos os layouts ficam dentro de um TabHost. Primeiro, temos um LinearLayout para os itens. Usamos um TabWidget para criar as abas e um FrameLayout para indicar os layouts que criamos para cada aba. Usamos o include para inserir o layout de cada aba:

<!-- Aba 1 -->

<include
   android:id="@+id/aba1"
   android:layout_width="fill_parent"
   android:layout_height="match_parent"
   layout="@layout/aba_um" >
</include>

Crie um layout para mostrarmos o TabHost (“layout_tabhost.xml”). Nele, vamos usar novamente o include para colocar o tabhost.xml:

<include
   android:id="@+id/tabs"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   layout="@layout/tabhost">
</include>

No OnCreateView, vamos codificar para carregar esse último layout:

else if (mItem.id == "2"){
   rootView = inflater.inflate(R.layout.layout_tabhost, container, false);

   TabHost myTabHost;

   myTabHost =(TabHost)rootView.findViewById(R.id.TabHost01);

   myTabHost.setup();

   TabHost.TabSpec spec = myTabHost.newTabSpec("tab_creation");

   spec.setIndicator("Aba 1",

      getResources().getDrawable(android.R.drawable.ic_menu_add));

   spec.setContent(R.id.aba1);

   myTabHost.addTab(spec);

   myTabHost.addTab(myTabHost.newTabSpec("tab_inser")

      .setIndicator("Aba 2",

      getResources().getDrawable(

      android.R.drawable.ic_menu_edit)).setContent(R.id.aba2));

}

Procuramos o TabHost usando o findViewById. Configuramos cada aba adicionando nome, usando a classe TabSpec. Veja o resultado na Figura 4 (ao abrir a app, selecione o Item 2).

 

Figura 4. Abas com TabHost

Abas com imagens

E se precisarmos (e sempre queremos) colocar imagens nas abas? É possível? Sim, mas usaremos XMLs para isso. Crie dois arquivos XML, mas na pasta drawable, com o nome de “icon_aba_um.xml” e “icon_aba_dois.xml”.

Nesses arquivos, vamos adicionar as imagens:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- imagem para quando a aba esta selecionada -->
    <item android:drawable="@drawable/ic_action_paste_selected"
       android:state_selected="true" />
    <!-- imagem para quando a aba não esta selecionada -->
    <item android:drawable="@drawable/ic_action_paste" />
</selector>

Note que temos que ter duas imagens: uma para quando a aba esta selecionada e outra para quando a mesma não esta selecionada. Adicione imagens desse tipo nas pastas drawable, lembrando de colocar imagens para cada tipo de tamanho.

Após criar os dois, temos que modificar o código do TabHost:

spec.setIndicator("",getResources().getDrawable(R.drawable.icon_aba_um));

...

myTabHost.addTab(myTabHost.newTabSpec("tab_inser")

   .setIndicator("",getResources().getDrawable(

   R.drawable.icon_aba_dois)).setContent(R.id.aba2));

Veja que removemos o nome da aba (necessário), e carregamos o XML criado usando getDrawable. Veja na Figura 5, como ficou as abas com as imagens.

 

Figura 5. Abas com imagens

ListView

Talvez um dos controles mais usados no Android. Nossos templates já possuem o ListView por padrão. Projeto dos artigos anteriores, o menu lateral é um ListView. Nesse template, a tela principal é um ListView. E o melhor, podemos customizá-los J.

Acesse o arquivo ItemListFragment.java e localize o método onCreate. Nele, temos o código que preenche o ListView:

setListAdapter(new ArrayAdapter<DummyContent.DummyItem>(
   getActivity(),
   android.R.layout.simple_list_item_activated_1,
   android.R.id.text1,
   DummyContent.ITEMS));

O setListAdapter, esta na classe ListFragment. Precisamos passar um adapter, e esta sendo criado um ArrayAdapter com o tipo DummyContent. Essa classe esta criada no nosso pacote, e lá que estão os itens do ListView:

addItem(new DummyItem("1", "Item 1"));
addItem(new DummyItem("2", "Item 2"));
addItem(new DummyItem("3", "Item 3"));

Modifique os valores para modificar a lista inicial. Podemos modificar o método onCreate para receber um array de strings por exemplo:

mDrawerListView.setAdapter(new ArrayAdapter<String>(
   getActionBar().getThemedContext(),
   android.R.layout.simple_list_item_1,
   android.R.id.text1,
   new String[]{
      getString(R.string.games),
      getString(R.string.groups),
      getString(R.string.settings),
}));

Nesse caso, passamos resources para os valores dos itens. O código é do projeto anterior que criamos.

Customizando um ListView

Para customizar um ListView, precisamos criar uma classe que herde de BaseAdapter e um arquivo XML que será o layout de cada item de um ListView. Primeiro, criaremos um layout chamado “single_item_listview.xml”. Adicione o seguinte código:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
   xmlns:android="http://schemas.android.com/apk/res/android"
   android:orientation="horizontal"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:padding="3dp">
 

   <ImageView
      android:id="@+id/thumbnail"
      android:layout_width="40dip"
      android:layout_height="40dip"
      android:scaleType="fitXY"/>

   <TextView
      android:id="@+id/item"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:layout_alignTop="@+id/thumbnail"
      android:layout_toRightOf="@+id/thumbnail"
      android:text="Item"
      android:textStyle="bold"
      android:textSize="15dip"
      android:paddingLeft="5dp"/>

   <TextView
      android:id="@+id/descrption"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:text="Description"
      android:layout_below="@+id/item"
      android:layout_toRightOf="@+id/thumbnail"
      android:layout_toEndOf="@+id/thumbnail"
      android:paddingLeft="5dp"/>
</RelativeLayout>

Colocamos um ImageView para mostrar uma imagem para o item, dois TextView para indicar o texto do item e uma descrição para o mesmo. Você pode configurar a propriedade Text do TextView apenas para visualizar no preeview como será o layout.

Vamos criar uma classe para ter os atributos do nosso item do ListView. Clique com o botão direito no pacote na pasta Java e escolha New>Pakage. Dê o nome de “Models”. Clique com o botão direito na pasta criada e escolha New>Java Class.

Dê o nome de “Item”. Adicione os atributos com o seguinte código:

private int Id;
private String sNmItem;
private String sDSItem;
private int iLogo;

Clique com o botão direito na classe, e escolha Refactor>Encapsulate Fields. Será aberto um editor, para marcar os atributos para o Android Studio gerar os métodos get e set (Figura 6).

 

Figura 6. Editor para criar os métodos dos atributos da classe

Clique em Refactor para os métodos serem criados.  Por fim, crie um novo construtor para a classe, para receber os valores dos atributos por parâmetro:

public Item(int id, String nmItem, String dsItem, int logo){
   this.Id = id;
   this.sNmItem = nmItem;
   this.sDSItem = dsItem;
   this.iLogo = logo;
}

Vamos agora, criar o Adapter, responsável por carregar esse ListView customizado. Crie uma nova pasta chamada “ListAdapter” e nela crie uma classe chamada “ListItem”. Como comentei, nossa classe terá de herdar de BaseAdapter, então, digite:

public class ListItem extends BaseAdapter

O código ficará com erro, então, acesse o ícone de uma lâmpada e clique no menu. Escolha Implement Methods. Um editor é aberto para escolhermos os métodos da classe BaseAdapter que usaremos (Figura 7).

 

Figura 7. Editor para criar os métodos da classe

Deixe todos os métodos selecionados e clique em OK. Vamos declarar alguns atributos e o Create dessa classe:

private Activity activity;
private static LayoutInflater inflater = null;
private List<Item> data;

public ListItem(Activity activity, List<Item> data) {
   this.activity = activity;
   this.data = data;
   inflater = (LayoutInflater)activity.getSystemService(
     Context.LAYOUT_INFLATER_SERVICE);
}

Declaramos como atributos um tipo Activity, LayoutInflater e uma lista de Item (modelo criado anteriormente). No construtor, recebemos uma Activity e a lista de itens. Repassamos os parâmetros para os atributos e carregamos o inflater, que ajudará a carregar o layout do item, criado antes.

O método getCount, deve retornar a quantidade de registros do adapter, então precisamos apenas chamar a variável data.size(). O getItem, deve retornar o item, de acordo com a posição passada como parâmetro, então digite:

return data.get(position);

O getItemId, quer o identificador do objeto, então, basta digitar:

Item item = (Item)this.getItem(position);
return item.getId();

Chamamos o getItem, e retornamos o id do Item. Por fim, o mais importante, o getView. Esse método que vamos preencher os controles do XML. Adicione o seguinte código:

View vi=convertView;
if(convertView == null)
   vi = inflater.inflate(R.layout.single_item_listview, null);

ImageView imagem = (ImageView)vi.findViewById(R.id.thumbnail);
TextView item = (TextView)vi.findViewById(R.id.item);
TextView description = (TextView)vi.findViewById(R.id.descrption);

Item itemObject = data.get(position);

item.setText(itemObject.getsNmItem());
description.setText(itemObject.getsDSItem());
imagem.setImageResource(itemObject.getiLogo());

return vi;

O parâmetro convertView será o responsável por carregar o layout que criamos (single_item_listview). Com esse layout carregado, podemos acessar os controles de tela para preencher os mesmos.

Usando a variável data, pegamos o dado e atribuímos aos controles. Simples. Para finalizar, precisamos criar a lista de itens e repassar o novo adapter para o ListView da nossa tela principal. Acesse o método onCreate e digite o seguinte código (comente o código do setListAdapter):

List<Item> lista = new ArrayList<Item>();
lista.add(new Item(1, "ProgressBar",
   "Controle para mostrar uma barra de progresso",
   R.drawable.ic_action_progressbar));
lista.add(new Item(2, "TabHost",
   "Controle para mostrar abas",
   R.drawable.ic_action_tabhost));
lista.add(new Item(3, "ListView",
   "Controle para mostrar dados em forma de lista",
   R.drawable.ic_action_listview));

setListAdapter(new ListItem(getActivity(), lista));

Criamos uma lista de itens, e no setListAdapter, chamamos a classe ListItem para preencher o ListView. Veja o resultado na Figura 8.

 

Figura 8. Customizando o ListView com textos e imagens

As imagens estão na pasta drawable. Mas para saber qual o item foi selecionado? Pegar suas informações que configuramos no ListItem? Crie um novo layout e adicione um ListView (layout_listview.xml).

Vamos fazer o mesmo exemplo, apenas colocando em um layout separado. No onCreate do ItemDetailFragment, digite:

else if (mItem.id == "3"){
rootView = inflater.inflate(R.layout.layout_listview, container, false);

//ListView

ListView lview = (ListView)rootView.findViewById(R.id.listView);
List<Item> lista = new ArrayList<Item>();

...

final ListItem adapter = new ListItem(getActivity(), lista);
lview.setAdapter(adapter);

lview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
   @Override
   public void onItemClick(AdapterView<?> parent, View view,
     int position, long id) {
     Item itemObject = (Item)adapter.getItem(position);

     Toast.makeText(getActivity(), " Id: " +
        itemObject.getId() + " Texto: " + itemObject.getsNmItem(),
        Toast.LENGTH_LONG).show();
  }
});
}

Carregamos o nosso layout, preenchemos a lista, igual ao exemplo anterior. Configuramos o Listener do ListView para o onItemClick. No evento, pegamos o objeto selecionado, e mostramos os dados.

Execute a aplicação, escolha o item (terceiro) na tela principal, aparecerá a lista customizada. Basta escolher um item para visualizar as informações do item selecionado (Figura 9).

 

Figura 9. Verificando qual item foi selecionado no ListView

Para customizar ainda mais, vamos colocar linhas antes os itens para realçar ainda mais o ListView. Digite no ListView:

android:divider="@android:color/black"
android:dividerHeight="1dp"

Podemos usar qualquer tamanho da linha, assim como cor. Veja na Figura 10, o ListView customizado.

 

Figura 10. Alterando cor e tamanho da linha divisória do ListView

Conclusões

Vimos neste artigo, mais controles de tela usados no Android. Conhecemos controles comuns em aplicações Android e aprendemos como customizá-los para que nossas aplicações fiquem o mais profissional possível. No próximo artigo conheceremos outros controles que facilitam o desenvolvimento Android.

Um grande abraço a todos e até a próxima!