Tutorial Android #5 – Aprimorando a Lista

Padrão

Olá pessoal! Prosseguindo com o tutorial sobre Android, vamos hoje aprimorar o nosso formulário. No último post, os Restaurantes, ao serem adicionados, eram listados na parte superior da tela. Com o post de hoje, eles passarão a ser listados com o endereço e um ícone identificando o tipo de restaurante que se trata.

O primeiro passo é criarmos o nosso próprio adaptador para exibir os itens na lista. Assim, na classe ListaRestaurantes, vamos criar uma classe interna, chamada AdaptadorRestaurante. Vai ficar assim:

package net.rafaeltoledo.restaurante;

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

import net.rafaeltoledo.restaurante.model.Restaurante;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.RadioGroup;

public class ListaRestaurantes extends Activity {

	List listaRestaurantes = new ArrayList();
	ArrayAdapter adaptador = null;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		Button salvar = (Button) findViewById(R.id.salvar);
		salvar.setOnClickListener(onSave);

		ListView lista = (ListView) findViewById(R.id.restaurantes);
		adaptador = new ArrayAdapter(this,
				android.R.layout.simple_list_item_1, listaRestaurantes);
		lista.setAdapter(adaptador);
	}

	private OnClickListener onSave = new OnClickListener() {

		public void onClick(View arg0) {
			Restaurante r = new Restaurante();
			EditText nome = (EditText) findViewById(R.id.nome);
			EditText endereco = (EditText) findViewById(R.id.end);

			r.setNome(nome.getText().toString());
			r.setEndereco(endereco.getText().toString());

			RadioGroup tipos = (RadioGroup) findViewById(R.id.tipos);

			switch (tipos.getCheckedRadioButtonId()) {
			case R.id.rodizio:
				r.setTipo("rodizio");
				break;
			case R.id.fast_food:
				r.setTipo("fast_food");
				break;
			case R.id.a_domicilio:
				r.setTipo("a_domicilio");
				break;
			}

			adaptador.add(r);
		}
	};

	class AdaptadorRestaurante extends ArrayAdapter {
		AdaptadorRestaurante() {
			super(ListaRestaurantes.this, android.R.layout.simple_list_item_1,
					listaRestaurantes);
		}
	}
}

O próximo passo é ajustarmos nosso layout para a nossa nova lista, já que  nessa nova listagem teremos nome, endereço e tipo (representado por uma imagem). Vamos, primeiramente, criar um layout que represente cada um dos itens da nossa listagem de forma a abrigar os três elementos. Na pasta res/layout crie o arquivo linha.xml e digite o seguinte conteúdo para ele:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:padding="4dip" >
	<ImageView android:id="@+id/icone"
	    android:layout_width="wrap_content"
	    android:layout_height="fill_parent"
	    android:layout_alignParentTop="true"
	    android:layout_alignParentBottom="true"
	    android:layout_marginRight="4dip"/>
    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <TextView android:id="@+id/titulo"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="center_vertical"
            android:textStyle="bold"
            android:singleLine="true"
            android:ellipsize="end"/>
        <TextView android:id="@+id/endereco"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="center_vertical"
            android:singleLine="true"
            android:ellipsize="end"/>
    </LinearLayout>
</LinearLayout>

Resumidamente, este layout divide cada item de listagem em duas partes (dois itens LinearLayout), sendo a primeira divisão de forma horizontal, onde à esquerda ficará a nossa imagem e, à direita, teremos outro LinearLayout, dessa vez vertical, que exibirá o nome do restaurante e o endereço.

O próximo passo é colocar as imagens em res/drawable. As imagens você pode baixar aqui. Se seu projeto tem vários diretórios chamados drawable (drawable-ldpi, por exemplo), renomeie o diretório drawable-mdpi para drawable e exclua os outros. Agora, coloque as três imagens baixadas nessa pasta.

Agora, vamos sobrescrever o método getView() na classe AdaptadorRestaurante. Este método é o responsável por exibir os itens na tela. Assim, vamos através dele utilizar o layout definido em linha.xml. Dessa forma, o arquivo ListaRestaurantes fica assim:

package net.rafaeltoledo.restaurante;

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

import net.rafaeltoledo.restaurante.model.Restaurante;
import android.app.Activity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.RadioGroup;
import android.widget.TextView;

public class ListaRestaurantes extends Activity {

	List listaRestaurantes = new ArrayList();
	ArrayAdapter adaptador = null;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		Button salvar = (Button) findViewById(R.id.salvar);
		salvar.setOnClickListener(onSave);

		ListView lista = (ListView) findViewById(R.id.restaurantes);
		adaptador = new ArrayAdapter(this,
				android.R.layout.simple_list_item_1, listaRestaurantes);
		lista.setAdapter(adaptador);
	}

	private OnClickListener onSave = new OnClickListener() {

		public void onClick(View arg0) {
			Restaurante r = new Restaurante();
			EditText nome = (EditText) findViewById(R.id.nome);
			EditText endereco = (EditText) findViewById(R.id.end);

			r.setNome(nome.getText().toString());
			r.setEndereco(endereco.getText().toString());

			RadioGroup tipos = (RadioGroup) findViewById(R.id.tipos);

			switch (tipos.getCheckedRadioButtonId()) {
			case R.id.rodizio:
				r.setTipo("rodizio");
				break;
			case R.id.fast_food:
				r.setTipo("fast_food");
				break;
			case R.id.a_domicilio:
				r.setTipo("a_domicilio");
				break;
			}

			adaptador.add(r);
		}
	};

	class AdaptadorRestaurante extends ArrayAdapter {
		AdaptadorRestaurante() {
			super(ListaRestaurantes.this, android.R.layout.simple_list_item_1,
					listaRestaurantes);
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {

			View linha = convertView;
			if (linha == null) {
				LayoutInflater inflater = getLayoutInflater();
				linha = inflater.inflate(R.layout.linha, null);
			}

			Restaurante r = listaRestaurantes.get(position);

			((TextView) linha.findViewById(R.id.titulo)).setText(r.getNome());
			((TextView) linha.findViewById(R.id.endereco)).setText(r.getEndereco());

			ImageView icone = (ImageView) linha.findViewById(R.id.icone);

			if (r.getTipo().equals("rodizio")) {
				icone.setImageResource(R.drawable.rodizio);
			} else if (r.getTipo().equals("fast_food")) {
				icone.setImageResource(R.drawable.fast_food);
			} else {
				icone.setImageResource(R.drawable.entrega);
			}

			return linha;
		}
	}
}

Prosseguindo, precisamos agora vincular os itens da lista à nossa lista de restaurantes adicionados. Para isso, vamos criar uma classe estática que armazenará os valores para que sejam adicionados à lista exibida na tela. Adicione-a após a declaração do nosso adaptador, de forma que o nosso arquivo ListaRestaurantes.java fique assim:

package net.rafaeltoledo.restaurante;

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

import net.rafaeltoledo.restaurante.model.Restaurante;
import android.app.Activity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.RadioGroup;
import android.widget.TextView;

public class ListaRestaurantes extends Activity {

	List listaRestaurantes = new ArrayList();
	ArrayAdapter adaptador = null;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		Button salvar = (Button) findViewById(R.id.salvar);
		salvar.setOnClickListener(onSave);

		ListView lista = (ListView) findViewById(R.id.restaurantes);
		adaptador = new ArrayAdapter(this,
				android.R.layout.simple_list_item_1, listaRestaurantes);
		lista.setAdapter(adaptador);
	}

	private OnClickListener onSave = new OnClickListener() {

		public void onClick(View arg0) {
			Restaurante r = new Restaurante();
			EditText nome = (EditText) findViewById(R.id.nome);
			EditText endereco = (EditText) findViewById(R.id.end);

			r.setNome(nome.getText().toString());
			r.setEndereco(endereco.getText().toString());

			RadioGroup tipos = (RadioGroup) findViewById(R.id.tipos);

			switch (tipos.getCheckedRadioButtonId()) {
			case R.id.rodizio:
				r.setTipo("rodizio");
				break;
			case R.id.fast_food:
				r.setTipo("fast_food");
				break;
			case R.id.a_domicilio:
				r.setTipo("a_domicilio");
				break;
			}

			adaptador.add(r);
		}
	};

	class AdaptadorRestaurante extends ArrayAdapter {
		AdaptadorRestaurante() {
			super(ListaRestaurantes.this, android.R.layout.simple_list_item_1,
					listaRestaurantes);
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {

			View linha = convertView;
			if (linha == null) {
				LayoutInflater inflater = getLayoutInflater();
				linha = inflater.inflate(R.layout.linha, null);
			}

			Restaurante r = listaRestaurantes.get(position);

			((TextView) linha.findViewById(R.id.titulo)).setText(r.getNome());
			((TextView) linha.findViewById(R.id.endereco)).setText(r.getEndereco());

			ImageView icone = (ImageView) linha.findViewById(R.id.icone);

			if (r.getTipo().equals("rodizio")) {
				icone.setImageResource(R.drawable.rodizio);
			} else if (r.getTipo().equals("fast_food")) {
				icone.setImageResource(R.drawable.fast_food);
			} else {
				icone.setImageResource(R.drawable.entrega);
			}

			return linha;
		}
	}

	static class ArmazenadorRestaurante {
		private TextView nome = null;
		private TextView endereco = null;
		private ImageView icone = null;

		ArmazenadorRestaurante(View linha) {
			nome = (TextView) linha.findViewById(R.id.titulo);
			endereco = (TextView) linha.findViewById(R.id.endereco);
			icone = (ImageView) linha.findViewById(R.id.icone);
		}

		void popularFormulario(Restaurante r) {
			nome.setText(r.getNome());
			endereco.setText(r.getEndereco());

			if (r.getTipo().equals("rodizio")) {
				icone.setImageResource(R.drawable.rodizio);
			} else if (r.getTipo().equals("fast_food")) {
				icone.setImageResource(R.drawable.fast_food);
			} else {
				icone.setImageResource(R.drawable.entrega);
			}
		}
	}
}

Agora, vamos fazer o método getView utilizar a classe ArmazenadorRestaurante para montar os objetos na lista, e alteramos as referências ao ArrayAdapter para o nosso AdaptadorRestaurante, finalizando o nosso tutorial. Lembre-se de também alterar, no construtor do nosso restaurante, a referência passada para o construtor da super-classe do nosso arquivo linha.xml.

package net.rafaeltoledo.restaurante;

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

import net.rafaeltoledo.restaurante.model.Restaurante;
import android.app.Activity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.RadioGroup;
import android.widget.TextView;

public class ListaRestaurantes extends Activity {

	List listaRestaurantes = new ArrayList();
	AdaptadorRestaurante adaptador = null;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		Button salvar = (Button) findViewById(R.id.salvar);
		salvar.setOnClickListener(onSave);

		ListView lista = (ListView) findViewById(R.id.restaurantes);
		adaptador = new AdaptadorRestaurante();
		lista.setAdapter(adaptador);

	}

	private OnClickListener onSave = new OnClickListener() {

		public void onClick(View arg0) {
			Restaurante r = new Restaurante();
			EditText nome = (EditText) findViewById(R.id.nome);
			EditText endereco = (EditText) findViewById(R.id.end);

			r.setNome(nome.getText().toString());
			r.setEndereco(endereco.getText().toString());

			RadioGroup tipos = (RadioGroup) findViewById(R.id.tipos);

			switch (tipos.getCheckedRadioButtonId()) {
			case R.id.rodizio:
				r.setTipo("rodizio");
				break;
			case R.id.fast_food:
				r.setTipo("fast_food");
				break;
			case R.id.a_domicilio:
				r.setTipo("a_domicilio");
				break;
			}

			adaptador.add(r);
		}
	};

	class AdaptadorRestaurante extends ArrayAdapter {
		AdaptadorRestaurante() {
			super(ListaRestaurantes.this, R.layout.linha,
					listaRestaurantes);
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {

			View linha = convertView;
			ArmazenadorRestaurante armazenador = null;

			if (linha == null) {
				LayoutInflater inflater = getLayoutInflater();
				linha = inflater.inflate(R.layout.linha, parent, false);
				armazenador = new ArmazenadorRestaurante(linha);
				linha.setTag(armazenador);
			} else {
				armazenador = (ArmazenadorRestaurante) linha.getTag();
			}

			armazenador.popularFormulario(listaRestaurantes.get(position));

			return linha;
		}
	}

	static class ArmazenadorRestaurante {
		private TextView nome = null;
		private TextView endereco = null;
		private ImageView icone = null;

		ArmazenadorRestaurante(View linha) {
			nome = (TextView) linha.findViewById(R.id.titulo);
			endereco = (TextView) linha.findViewById(R.id.endereco);
			icone = (ImageView) linha.findViewById(R.id.icone);
		}

		void popularFormulario(Restaurante r) {
			nome.setText(r.getNome());
			endereco.setText(r.getEndereco());

			if (r.getTipo().equals("rodizio")) {
				icone.setImageResource(R.drawable.rodizio);
			} else if (r.getTipo().equals("fast_food")) {
				icone.setImageResource(R.drawable.fast_food);
			} else {
				icone.setImageResource(R.drawable.entrega);
			}
		}
	}
}

Agora, se executarmos nosso aplicativo, teremos os itens adicionados à lista com seus respectivos ícones, de acordo com a categoria selecionada. O aplicativo em execução ficará assim:

Pra quem perdeu alguma parte, ou quiser baixar os resources utilizados, o projeto pode ser baixado aqui.

É isso pessoal! Espero que estejam gostando do tutorial 🙂

8 comentários sobre “Tutorial Android #5 – Aprimorando a Lista

  1. André Kunde

    Muito bom esse seu tutorial, Parabens!!

    Estou acompanhando ele e tive um pouco de dificuldades nesta parte (#5).
    Depois de ter conferido 2 vezes o projeto todo, resolvi baixar o projeto completo para conferir e notei que o arquivo ListaRestaurantes.java esta um pouco diferente.

    • Opa, valeu André! Realmente, me lembrando agora, teve um post onde eu fiz o exemplo passo a passo e no final ele não rodou. Aí eu garimpei o código atrás de erro e acho que esqueci de atualizar no tutorial. A hora que tiver um tempinho eu faço uma revisão nele.

      De qualquer forma, continue acompanhando e obrigado pela visita! 🙂

  2. Eduardoxvii

    Tive que fazer um casting na linha 89 para evitar erro:
    armazenador.popularFormulario((Restaurante)listaRestaurantes.get(position));

  3. Lucas

    Boa tarde Rafael estou com um problema envolvendo listas no android, preciso colocar um edittext como componente da linha mas, ao editar o conteudo de qualquer um da dos que aparece na tela todos os demais assumem o mesmo valor e, ao rolar a lista para exibir as demais linhas os campos voltam ao valor inicial.
    Como faço para resolver esse problema?
    Grato pela ajuda,

    Lucas P. Rosseti

Deixe uma resposta