Introdução

Uma ListView, como o próprio nome já diz, é uma lista rolada de views. Todo componente da interface gráfica do Android é considerado uma View pois a estende.

O conceito de uma lista customizada é: preencher um array de objetos referente ao seu item, criar um adaptador que vai ficar responsável por atualizar os dados na tela e definir o adaptador no seu ListView. Bem simples.

Exemplo de uma lista personalizada
Figura 1: Exemplo de uma lista personalizada.

Codificando

Começamos a codificar pela parte mais básica, o XML do ListView, o main.xml. Vamos definir nele somente um ListView e configurar algumas coisas, por exemplo: uma cor de fundo para nosso LinearLayout android:background a cor do divisor de itens do ListView android:divider sua espessura android:dividerHeight e um id android:id.

Listagem 1: Código do main.xml.

<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout 
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#FFFFFFFF"
>    
        <ListView
        android:id="@+id/list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:divider="#FFECECEC"
        android:dividerHeight="2sp"
        />    
</LinearLayout>

Agora que temos nossa lista, precisamos dos itens, para isso vamos criar o XML responsável por eles, o item_list.xml. Em nosso item vamos inserir uma imagem e um texto em uma linha horizontal.

Foi inserido um LinearLayout horizontal android:orientation para nossa linha e dentro dela um ImageView responsável pela imagem e um TextView que terá seu texto centralizado verticalmente android:gravity com uma margem a esquerda para que não fique junto a imagem android:layout_marginLeft.

Listagem 2: Código do item_list.xml.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    android:padding="5sp">
    <ImageView
        android:id="@+id/imagemview"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
            />

    <TextView
        android:id="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginLeft="5sp"
        android:gravity="center_vertical"
        android:textColor="#FF000000"
        />
</LinearLayout> 

Toda a parte do layout já foi definida com esses dois arquivos, agora o próximo passo é criar nossa classe que vai popular os itens e o adaptador deixando por último a que vai controlar tudo isso.

Na classe do item da lista, vamos definir somente dois atributos: o texto e o id da imagem. Definimos o ID porque sabemos que para todas as imagens inseridas na pasta /res/drawable é gerado um id assim como os ids definidos pelo layout XML, porém esses ids ficam em R.drawable., permitindo que o sistema fique mais leve já que não vamos trabalhar com a imagem inteira carregada na memória.

Listagem 3: Código da classe ItemListView referente ao nosso item.

public class ItemListView {

    private String texto;
    private int iconeRid;

    public ItemListView() {
    this("", -1);
    }

    public ItemListView(String texto, int iconeRid) {
        this.texto = texto;
        this.iconeRid = iconeRid;
    }

    public int getIconeRid() {
        return iconeRid;
    }

    public void setIconeRid(int iconeRid) {
        this.iconeRid = iconeRid;
    }

    public String getTexto() {
        return texto;
    }

    public void setTexto(String texto) {
        this.texto = texto;
    }
}

Agora vamos criar a classe mais “complicada” deste artigo: o adaptador. Como dito anteriormente, ele se encarregará de todo controle de atualização dos itens na lista.

A nossa classe AdapterListView deve estender BaseAdapter para que nossa lista aceite-a como um adaptador. Vamos ter somente dois atributos, o LayoutInflater que será construído no construtor da classe para inflar o layout XML como uma view, com isso vamos ter acesso a todos seus atributos, e nossa lista de itens ItemListView que preencherá a lista. Em seu construtor vamos passar um context que fica responsável pela construção do LayoutInflater e a lista que vai ser atribuído ao atributo da classe.

Listagem 4: Início da classe AdapterListView e seu construtor.

public class AdapterListView extends BaseAdapter {

    private LayoutInflater mInflater;
    private List<ItemListView> itens;

    public AdapterListView(Context context, List<ItemListView> itens) {
        //Itens do listview
        this.itens = itens;
        //Objeto responsável por pegar o Layout do item.
        mInflater = LayoutInflater.from(context);
    }

[...]

Como o BaseAdapter vem de uma interface chamada Adapter, ele precisa implementar os métodos getCount(), getItem(), getItemId() e getView(). O getCont() retorna a quantidade de itens da lista, o getItem() irá retornar o item da lista de acordo com sua posição e o getItemId irá retornar o id do item de acordo com sua posição, mas não vamos implementar esse método pois não estamos trabalhando com ids independentes.

Listagem 5: Métodos necessários para implementação do BaseAdapter.

[...]

    public int getCount() {
        return itens.size();
    }
    public ItemListView getItem(int position) {
        return itens.get(position);
    }
    public long getItemId(int position) {
        return position;
    }

[...]

O getView() é nosso método principal, ele é o atualizador da lista, que é frequentemente atualizada e a cada vez, esse método é executado de acordo com a quantidade de itens do getCont(). Ele recebe 3 parametros: a posição, a view da atualização anterior que é nosso layout já carregado (desatualizado) e o ViewGroup que é (se houver) o “pai” da view.

Vamos criar uma classe interna chamada ItemSuporte que vai ter as views de nosso layout. Essa classe é criada para nos proporcionar uma rápida atualização para não que não seja preciso carregar todos os dados novamente. Se nossa view não existir, vamos inflá-la (carregar) através do atributo LayoutInflater que foi criado no construtor da classe. Após o layout ser carregado e atribuído à view, vamos criar o ItemSuporte inserindo as views do item_list em seu interior. Depois de inserido, definimo-lo como uma tag da view pelo método setTag(), pois se a view já existisse nós apenas carregaríamos o ItemSuporte pelo getTag().

Após carregar ou criar a view, adicionamos o ItemListView respectivo à posição da lista e atualizamos os dados da nossa view pelos dados do nosso item e no final do método retornamos a view com os dados atualizados.

Listagem 6: Método getView(), o atualizador da lista.

[...]

    public View getView(int position, View view, ViewGroup parent) {
        ItemSuporte itemHolder;
        //se a view estiver nula (nunca criada), inflamos o layout nela.
        if (view == null) {
            //infla o layout para podermos pegar as views
            view = mInflater.inflate(R.layout.item_list, null);

            //cria um item de suporte para não precisarmos sempre
            //inflar as mesmas informacoes
            itemHolder = new ItemSuporte();
            itemHolder.txtTitle = ((TextView) view.findViewById(R.id.text));
            itemHolder.imgIcon = ((ImageView) view.findViewById(R.id.imagemview));

            //define os itens na view;
            view.setTag(itemHolder);
        } else {
            //se a view já existe pega os itens.
            itemHolder = (ItemSuporte) view.getTag();
        }

        //pega os dados da lista
        //e define os valores nos itens.
        ItemListView item = itens.get(position);
        itemHolder.txtTitle.setText(item.getTexto());
        itemHolder.imgIcon.setImageResource(item.getIconeRid());

        //retorna a view com as informações
        return view;
    }

    /**
     * Classe de suporte para os itens do layout.
     */
    private class ItemSuporte {

        ImageView imgIcon;
        TextView txtTitle;
    }
}

Conclusão

Utilizando um ListView customizado você tem um controle bem maior da sua interface. Apesar do controle de informação ser bem maior, seu uso porém pode ser dificultoso, no entanto veja se realmente tem a necessidade para poupar seu tempo.

Com isso finalizo esse artigo. Em anexo segue o projeto que foi utilizado como exemplo. Até o próximo, um grande abraço e obrigado.

Referências