sábado, 10 de dezembro de 2011

Android - ListView Parte 6

Olá,

Dando sequência a série sobre ListView, esse que é um dos recursos mais importantes do Android, estamos chegando a parte 6.

Hoje daremos sequência na parte 5, iremos ver como mudar a cor do listview, utilizar o AlertDialog e implementar mais performance no nosso custom Adapter.

O fonte será parecido com o último post.

Abaixo segue o fonte utilizado todo comentado para facilitar seu aprendizado:

Arquivo estados.java:
package br.com.empresa;

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener;

public class list12 extends Activity {
    //Criamos uma lista de Estados baseados na classe Estado
    private List<estado> lstEstados;
    ListView list;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
  
        setContentView(R.layout.list12);
  
        list = (ListView) findViewById(R.id.ListView12);

        //Iniciamos a lista de Estados
        //no método add já inserimos um novo registro de cada Estados desejado
        lstEstados = new ArrayList<estado>();
        lstEstados.add(new Estado("Sao Paulo", "Sao Paulo", R.drawable.saopaulo));
        lstEstados.add(new Estado("Rio de Janeiro", "Rio de Janeiro", R.drawable.riodejaneiro));
        lstEstados.add(new Estado("Minas Gerais", "Belo Horizonte", R.drawable.minasgerais));
        lstEstados.add(new Estado("Rio Grande do Sul", "Porto Alegre", R.drawable.riograndedosul));
        lstEstados.add(new Estado("Santa Catarina", "Florianópolis", R.drawable.santacatarina));
        lstEstados.add(new Estado("Paraná", "Curitiba", R.drawable.parana));
        lstEstados.add(new Estado("Mato Grosso", "Cuiabá", R.drawable.matogrosso));
        lstEstados.add(new Estado("Amazonas", "Manaus", R.drawable.amazonas));

        //Criação do Adapter e passamos a nossa lista de Estados para ele
        EstadoAdapter adapter = new EstadoAdapter(this, lstEstados);

        //referenciamos a função que será invocada quando o usuário
        //clicar em algum item da lista
        list.setOnItemClickListener(onItemClick_List);
        
        list.setAdapter(adapter);
        
        //caso seja preciso adicionar mais algum item na lista você
        //pode utilizar também a forma abaixo
        adapter.addItem(new Estado("Bahia", "Salvador", R.drawable.bahia));
    }

        
    OnItemClickListener onItemClick_List = new OnItemClickListener() {
        public void onItemClick(AdapterView arg0, View view, int position, long index) {
            //Pegar o item clicado
            showToast("Você clicou no estado : " + lstEstados.get(position).getEstado());
        }
    };
 

    //Quando tecla no botão voltar o sistema irá apresentar
    //uma caixa de diálogo quetionando se realmente desej sair
    @Override 
    public void onBackPressed() {     
        AlertDialog.Builder builder = new AlertDialog.Builder(this);     
        builder.setMessage("Deseja sair?")            
        .setCancelable(false)        
        .setIcon(android.R.drawable.ic_dialog_alert) // ícone de alerta
        .setTitle("Atenção:") //título do caixa de diálogo
                
        //Evento disparado se clicar no botão Sim
        .setPositiveButton("Sim", new DialogInterface.OnClickListener() {               
            public void onClick(DialogInterface dialog, int id) {                     
                list12.this.finish(); //Fecha o Activity     
            }            
        })            
  
        //Event disparado se clicar no botão Não
        .setNegativeButton("Não", new DialogInterface.OnClickListener() {                
            public void onClick(DialogInterface dialog, int id) {                     
                dialog.cancel(); //Cancela a caixa de diálogo e volta a tela anterior
            }            
        });     
        AlertDialog alert = builder.create();     
        alert.show(); //Chama a caixa de diálogo
    }  
 
 
    private void showToast(String message) {
        Toast.makeText(this, message, Toast.LENGTH_LONG).show();
    }     
}


Arquivo EstadoAdapter.java:
package br.com.empresa;

import java.util.List;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

public class EstadoAdapter extends BaseAdapter{
    private List<estado> listEstados;
    Context context;

    //Classe utilizada para instanciar os objetos do XML
    private LayoutInflater inflater;
    
    public EstadoAdapter(Context context, List<estado> plistEstados) {
        this.listEstados = plistEstados;
        this.context = context;
        inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    public void addItem(final Estado item) {
        this.listEstados.add(item);
        //Atualizar a lista caso seja adicionado algum item
        notifyDataSetChanged();
    }    
    
    @Override
    public int getCount() {
        return listEstados.size();
    }

    @Override
    public Object getItem(int position) {
        return listEstados.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup viewGroup) {
        
        Estado estadoVO = listEstados.get(position);

        //O ViewHolder irá guardar a instâncias dos objetos do estado_row
        ViewHolder holder;
  
        //Quando o objeto convertView não for nulo nós não precisaremos inflar
        //os objetos do XML, ele será nulo quando for a primeira vez que for carregado
        if (convertView == null) {
            convertView = inflater.inflate(R.layout.estado_row, null);
   
            //Cria o Viewholder e guarda a instância dos objetos
            holder = new ViewHolder();
            holder.bandeira = (ImageView) convertView.findViewById(R.id.bandeira);
            holder.tvEstado = (TextView) convertView.findViewById(R.id.tvEstado);
            holder.tvCapital = (TextView) convertView.findViewById(R.id.tvCapital);
   
            convertView.setTag(holder);
        } else {
            //pega o ViewHolder para ter um acesso rápido aos objetos do XML
            //ele sempre passará por aqui quando,por exemplo, for efetuado uma rolagem na tela 
            holder = (ViewHolder) convertView.getTag();
        }

        holder.bandeira.setImageResource(estadoVO.getBandeira());
        holder.tvEstado.setText(estadoVO.getEstado());
        holder.tvCapital.setText(estadoVO.getCapital());

        return convertView;

    }
 
    //Criada esta classe estática para guardar a referência dos objetos abaixo
    static class ViewHolder {
        public ImageView bandeira;
        public TextView tvEstado;
        public TextView tvCapital;
    }
}

Abaixo segue o código fonte do arquivo estados.xml:
<?xml version="1.0" encoding="utf-8"?>  
<LinearLayout 
    android:layout_height="match_parent" 
    android:layout_width="match_parent"
    xmlns:android="http://schemas.android.com/apk/res/android">
    <ListView 
        android:id="@+id/ListView12" 
        android:layout_height="wrap_content" 
        android:layout_width="fill_parent">
    </ListView>
</LinearLayout>


Abaixo segue o código fonte do arquivo estado_row.xml:
Atenção: neste arquivo abaixo você fará referência a o outros dois arquivos (list_gb.xml e text_bg.xml) através das propriedades android:background="@color/list_bg" e style="@style/FontBold"
<?xml version="1.0" encoding="utf-8"?>  
<LinearLayout 
    android:background="@color/list_bg" 
    android:id="@+id/LinearLayout01" 
    android:layout_height="wrap_content" 
    android:layout_margintop="10dp" 
    android:layout_width="fill_parent" 
    android:orientation="vertical" 
    xmlns:android="http://schemas.android.com/apk/res/android">
        <RelativeLayout 
            android:id="@+id/LinearLayout02" 
            android:layout_height="wrap_content" 
            android:layout_marginbottom="3dp" 
            android:layout_margintop="3dp" 
            android:layout_width="fill_parent">
            <ImageView 
                android:focusable="false" 
                android:id="@+id/bandeira" 
                android:layout_height="wrap_content" 
                android:layout_width="wrap_content" 
                android:src="@drawable/icon"/>                  
            <TextView 
                style="@style/FontBold"
                android:id="@+id/lblEstado" 
                android:layout_torightof="@+id/bandeira" 
                android:text="Estado : "/>
            <TextView 
                style="@style/FontBold"
                android:id="@+id/tvEstado" 
                android:layout_torightof="@+id/lblEstado" 
                android:text="nome do estado"/>
            <TextView 
                style="@style/FontPadrao"                
                android:id="@+id/lblCapital" 
                android:layout_below="@+id/lblEstado" 
                android:layout_torightof="@+id/bandeira" 
                android:text="Capital : "/>
            <TextView 
                style="@style/FontPadrao"
                android:id="@+id/tvCapital" 
                android:layout_below="@+id/lblEstado" 
                android:layout_torightof="@+id/lblCapital" 
                android:text="nome da capital"/>
        </ImageView>
    </RelativeLayout>
</LinearLayout>

Abaixo segue o código fonte do arquivo list_bg.xml (este arquivo deverá ficar na pasta res\color):
<?xml version="1.0" encoding="utf-8"?>  
     
    <item 
        android:drawable="@color/white" 
        android:state_pressed="false" 
        android:state_selected="false"/>      
    <item 
        android:drawable="@color/black" 
        android:state_pressed="true"/>      
    <item 
        android:drawable="@color/black" 
        android:state_pressed="false" 
        android:state_selected="true"/>    
 


Abaixo segue o código fonte do arquivo text_bg.xml (este arquivo deverá ficar na pasta res\color):
<?xml version="1.0" encoding="utf-8"?>  
     
    <item 
        android:color="@color/black" 
        android:state_pressed="false" 
        android:state_selected="false"/>
    <item 
        android:color="@color/white" 
        android:state_pressed="true"/>      
    <item 
        android:color="@color/white" 
        android:state_pressed="false" 
        android:state_selected="true"/>    
 

Abaixo segue o código fonte do arquivo styles.xml (este arquivo deverá ficar na pasta res\values):
<?xml version="1.0" encoding="utf-8"?>  
<resources>
    <style name="FontBold" parent="@android:style/TextAppearance.Medium">
        <item name="android:layout_width">wrap_content
        <item name="android:layout_height">wrap_content
        <item name="android:textStyle">bold
        <item name="android:focusable">false
        <item name="android:typeface">sans 
        <item name="android:textSize">16sp
        <item name="android:textColor">@color/text_bg  
    </style>
    <style name="FontPadrao" parent="@android:style/TextAppearance.Medium">
        <item name="android:layout_width">wrap_content
        <item name="android:layout_height">wrap_content
        <item name="android:focusable">false
        <item name="android:typeface">sans 
        <item name="android:textSize">13sp
        <item name="android:textColor">@color/text_bg
    </style>
</resources> 

Abaixo segue o código fonte do arquivo colors.xml (deverá ficar na pasta res\values):
<?xml version="1.0" encoding="utf-8"?> 
<resources>     
    <color name="white">#fff</color>     
    <color name="black">#000</color>     
    <color name="red">#c6360a</color>     
    <color name="green">#688f2b</color>     
    <color name="orange">#f48905</color>     
    <color name="dark_blue">#003366</color>         
    <color name="grey">#888888</color> 
</resources> 

Os arquivos acima serão os responsáveis por mudar a cor listview e dos textview que ele possui, ele deverão ficar na pasta res\color, conforme figura abaixo:


Abaixo segue o resultado de nosso programa:
ListView

ListView


Abaixo segue algumas dicas para melhor entendimento do fonte:

  1. Arquivo style.xml - atributos dos textview que utilizamos em nosso fonte
  2. Arquivo list_bg.xml - definição de cores do nosso listview
  3. Arquivo text_bg.xml - definição das cores dos textview utilizados no arquivo estado_row.xml
  4. Utilização da classe ViewHolder no arquivo EstadoAdapter.java para aumentar a performance ao carregar os itens da lista.
  5. Utilização da classe AlertDialog para exibir ao usuário a opção de escolher entre duas ações.


Por enquanto é isso espero que tenham gostado e em breve estarei postando mais discas e tutoriais sobre listview e layout.



Trabalhando com Banco de Dados SQLite:
http://escoladeandroid.blogspot.com/2012/02/android-criando-uma-agenda-de-contatos.html

Desenvolvi o jogo Circus Puzzle Free ele é um quebra-cabeça e está publicado no Android Market, agradeço a todos que baixarem, jogarem e comentarem.



Desenv com qualidade!

10 comentários:

lucena disse...

Totalmente didático. Sou novo nesta linguagem (tanto Android quanto Java) mas quando encontro recursos tão bem explicados não posso deixar de comentar. Parabéns

Marcio de Souza disse...

Lucena,

Valeu pelo comentário, continue visitando que em breve estarei postando mais novidades.

Obrigado

Rafael Sousa disse...

Parabéns pelo blog. Pela qualidade do material postado aqui, com certeza serei frequentador assíduo.

Marcio de Souza disse...

Obrigado, Rafael

Agora em Fevereiro de 2012 estarei postando um tutorial referente a banco de dados SQLite.

Anônimo disse...

Porque utilizar a classe ViewHolder
como static ?

Marcio de Souza disse...

Olá,

Só para entender, a cada item de nossa Lista/ListView ele executa o método getView, e por isso a classe foi criada com Static, para ganhar em performance, pois uma vez criada e atribuída os valores/objetos a ela, nós não precisamos mais criá-la novamente

holder = new ViewHolder();
holder.bandeira = (ImageView) convertView.findViewById(R.id.bandeira);
holder.tvEstado = (TextView) convertView.findViewById(R.id.tvEstado);
holder.tvCapital = (TextView) convertView.findViewById(R.id.tvCapital);

Espero ter conseguido explicar.

Obrigado pela visita!

Anônimo disse...

Márcio, parabéns pelo blog e pelas postagens, realmente são muito boas. Estou precisando de uma help e acho que você pode ajudar: preciso importar uma base de dados sqlite pronta para a aplicação e exibir seus dados numa listview, tem como? Podias criar um tutorial explicando

Marcio de Souza disse...

Olá, Amigo

Não sei vou conseguir te ajudar em 100%, mas eu escrevi um artigo sobre Banco de Dados SQLite e Android e está publicado no link a seguir
http://escoladeandroid.blogspot.com/2012/02/android-criando-uma-agenda-de-contatos.html ficarei feliz te servir em alguma coisa.

Até mais...

Anônimo disse...

Márcio,

Parabéns pelos posts, ajudou bastante com muitas dúvidas que tinha com relação à listview, mas estou com uma agora que já procurei e não consegui êxito na procura e talvez você possa ajudar. Tenho um listview por exemplo com 10 itens e preciso que 3 desses itens ou fiquem com cor de fundo diferente ou com a cor da letra diferente, independente da seleção, de acordo com um critério específico. Você tem idéia de como resolver isso ?

Marcio de Souza disse...

Olá, Amigo Anônimo

Logo estarei postando mais uma opção de listview com ests funcionalidade que você deseja.