12 Abr, 2012 20:30

Criando lista com seções em Android - Revisitado

Os métodos são:

// número de seções da lista
abstract protected int getSectionCount();

// número de itens de uma dada seção
abstract protected int getItemCountForSection(int sectionIndex);

// objeto associado a um dado item de uma dada seção
abstract protected Object getItemForSection(int sectionIndex, int itemIndex);

// id de um dado item de uma dada seção
abstract protected long getItemIdForSection(int sectionIndex, int itemIndex);

// view associada a uma dada seção
abstract protected View getSectionView(int sectionIndex, View convertView, ViewGroup parent);

// view associado a um dado item de uma dada seção
abstract protected View getSectionItemView(int sectionIndex, int itemIndex, View convertView, ViewGroup parent);

Esses métodos permitem ao programador utilizar uma estrutura de dados totalmente coerente com a apresentação, i.e. um array de objetos tipo "Seção" que, por sua vez, possuem um array de objetos tipo "Item". Com isso, uma implementação de uma subclasse do nosso adapter poderia ser:

ArrayList<Secao> secoes;

@Override
protected int getSectionCount() {
    return secoes.size;
}

@Override
protected int getItemCountForSection(int sectionIndex) {
    return secoes.get(sectionIndex).getItems().size
}

@Override
protected Object getItemForSection(int sectionIndex, int itemIndex) {
    return secoes.get(sectionIndex).getItems().get(itemIndex);
}

@Override
protected long getItemIdForSection(int sectionIndex, int itemIndex) {
    return secoes.get(sectionIndex).getItems().get(itemIndex).getId();
}

@Override
protected View getSectionView(int section, View convertView, ViewGroup parent) {
    TextView view = (TextView) convertView;

    if (view == null) 
        view = (TextView) inflater.inflate(R.layout.section_item, null);

    view.setText(secoes.get(section).getNome());
    return view;
}

@Override
protected View getSectionItemView(int section, int item, View convertView, ViewGroup parent) {
    TextView view = (TextView) convertView;

    if (view == null) 
        view = (TextView) inflater.inflate(R.layout.list_item, null);

    view.setText(secoes.get(sectionIndex).getItems().get(itemIndex).getNome());
    return view;
}

E o resultado seria:

ListView em Android com seções

Muito simples, não?

E o tratamento de eventos na lista? O SectionAdapter serve de fachada entre os métodos comuns de ListAdapter e os métodos especiais que apresentei acima. Sendo assim, é possível tratar o SectionAdapter como um adapter normal na hora de tratar os eventos. Ex:

@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
    super.onListItemClick(l, v, position, id);

    //SectionAdapter responde corretamente a getItem e getItemId sem necessidade de qualquer implementação extra
    Item item = (Item)sectionAdapter.getItem(position);

    Intent intent = new Intent(getApplicationContext(), LojaActivity.class);
    intent.putExtra("item", item);
    startActivity(intent);
}

Limitação: atualmente, o SectionAdapter divide os tipos de view em dois (section e item), o que define o comportamento do reaproveitamento das views no getView. Caso haja a necessidade de haver mais de um tipo de view para seções ou itens, será necessário mexer diretamente na implentação de SectionAdapter. Se um dia eu fizer essa mudança, volto aqui e compartilho com vocês. ;)

Você pode baixar o código-fonte necessário para usar o SectionAdapter aqui. Qualquer sugestão será bem vinda.

Ao navegar neste site, você consente o uso de cookies nossos e de terceiros, que coletam informações anônimas e são essenciais para melhorar sua experiência em nosso site.