Tutorial Android #4 – Adicionando uma Lista

Padrão

Olá pessoal! No tutorial de hoje da série sobre Android, vamos começar a adicionar funcionalidade ao nosso aplicativo. Com o post de hoje, conseguiremos adicionar os restaurantes, que serão listados no aplicativo.

Começando a colocar a mão na massa, o primeiro passo é trocarmos a instância única da classe Restaurante por uma lista de objetos. Porém, a simples mudança acarretará alguns erros no código. Assim, também precisaremos montar o objeto no método onClick e o adicionarmos na lista. Com essas alterações, o nosso arquivo ListaRestaurantes.java 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.Button;
import android.widget.EditText;
import android.widget.RadioGroup;

public class ListaRestaurantes extends Activity {

	List<Restaurante> listaRestaurantes = new ArrayList<Restaurante>();

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

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

	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;
			}

			listaRestaurantes.add(r);
		}
	};
}

Basicamente, o que fizemos foi retirar o objeto r que estava no escopo da classe e o colocamos no método onClick. Além disso, criamos a lista chamada listaRestaurantes como um atributo da classe, e ao final do método onClick, adicionamos o objeto à lista.

O próximo passo é implementarmos o método toString() da classe Restaurante, já que ele será chamado quando os restaurantes forem listados. Para o nosso objetivo, nos interessa apenas o nome do restaurante, de forma que o método toString() pode retornar o método getNome(). Dessa forma, nossa classe Restaurante fica assim:

package net.rafaeltoledo.restaurante.model;

public class Restaurante {

	private String nome = "";
	private String endereco = "";
	private String tipo = "";

	public String getNome() {
		return nome;
	}

	public void setNome(String nome) {
		this.nome = nome;
	}

	public String getEndereco() {
		return endereco;
	}

	public void setEndereco(String endereco) {
		this.endereco = endereco;
	}

	public String getTipo() {
		return tipo;
	}

	public void setTipo(String tipo) {
		this.tipo = tipo;
	}

	@Override
	public String toString() {
		return getNome();
	}
}

Agora temos a parte mais desafiadora, que é exatamente mostrar a lista de restaurantes na tela de acordo que formos adicionando-os. Uma forma de fazer isso é utilizando o RelativeLayout, de forma que o formulário permaneça na parte de baixo da tela e os restaurantes adicionados sejam listados na parte superior. Vamos alterar o arquivo main.xml para que fique com esse aspecto:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
	<TableLayout android:id="@+id/detalhes"
    	android:layout_width="fill_parent"
    	android:layout_height="wrap_content"
    	android:layout_alignParentBottom="true"
    	android:stretchColumns="1">
    	<TableRow>
        	<TextView android:text="Nome:"/>
        	<EditText android:id="@+id/nome"/>
    	</TableRow>
    	<TableRow>
        	<TextView android:text="Endereço:"/>
        	<EditText android:id="@+id/end"/>
    	</TableRow>
    	<TableRow>
        	<TextView android:text="Tipo:"/>
        	<RadioGroup android:id="@+id/tipos">
            	<RadioButton android:id="@+id/rodizio"
                	android:text="Rodízio"/>
            	<RadioButton android:id="@+id/fast_food"
                	android:text="Fast Food"/>
            	<RadioButton android:id="@+id/a_domicilio"
                	android:text="A Domicílio"/>
        	</RadioGroup>
    	</TableRow>
    	<Button android:id="@+id/salvar"
        	android:layout_width="fill_parent"
        	android:layout_height="wrap_content"
        	android:text="Salvar"/>
	</TableLayout>
	<ListView android:id="@+id/restaurantes"
	    android:layout_width="fill_parent"
	    android:layout_height="wrap_content"
	    android:layout_alignParentTop="true"
	    android:layout_above="@id/detalhes"/>
</RelativeLayout>

Basicamente o que fizemos foi englobar o TableLayout que tínhamos dentro do RelativeLayout, ajustando suas dimensões. Além disso, tivemos também um item chamado ListView, definido pelo nome restaurantes, que será quem armazenará a nossa lista de restaurantes. Um importante parâmetro é o android:layout_above que indicará que nosso TableLayout, agora nomeado como detalhes, será exibido logo em seguida ao nosso RelativeLayout.

Se executarmos nosso aplicativo agora, ele deverá ter essa aparência:

Agora, precisamos fazer alguns ajustes na nossa Activity para que os elementos sejam adicionados e listados. Abra o arquivo ListaRestaurantes.java novamente e edite-o:

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<Restaurante> listaRestaurantes = new ArrayList<Restaurante>();
	ArrayAdapter<Restaurante> 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<Restaurante>(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);
		}
	};
}

O que fizemos foi adicionar o elemento adaptador, do tipo ArrayAdapter. É ele quem fará a montagem dos restaurantes adicionados na tela. Definimos a forma como ele funcionará em seu construtor, na linha 31, indicando o segundo parâmetro android.R.layout.simple_list_item_1, dizendo que será uma lista da classe Restaurante, e passando o parâmetro listaRestaurantes. Vinculamos o adaptador, então, ao item ListView que foi declarado no main.xml, e que o obtemos através do método findViewById(). Assim, chamamos seu método setAdapter e passamos o nosso adaptador.

Ao final, no método onClick, ao invés de adicionarmos o restaurante à lista, adicionamos ao adaptador. O resultado será a lista de restaurantes sendo criada em nosso aplicativo:

Bom, por hoje é isso! Pra quem teve problemas, pode baixar o projeto aqui.

Até a próxima!

  • Marcos

    ola Post muito bom..
    estive tentando usar esse codigo e topei com um problema
    esse array eu colocque na classe Restarante porque precisava sair e entrar de novo na tela a onde esta a lista,mas toda vez q faço isso o meu array fica vazio porque ?

    • Se eu entendi bem, é porque a classe Restaurante é instanciada toda vez que o formulário é exibido, é criada uma nova entidade da classe Restaurante. Como boas práticas de arquitetura, a classe Restaurante é uma classe de entidade, ou seja, representa um restaurante. Portanto, ao meu ver, não faz muito sentido colocar a lista dentro dela…

      • Marcos

        ola obrigado pela resposta..
        Mas a onde eu deveria colocar
        estou fazendo isso e porque vou ter 2 telas, uma de menu e outra de compra
        o cliente tem a possibilidade de navegar nas outras telas que estao no menu tipo “promoções etc..”ao voltar na tela de compra tem q achar a lista cheia de item q ele ja comprou
        como posso resolver esse problema sem precisar gravar no banco ja tentei ate fazer outro array mas da na mesma

        obrigado
        Marcos Paulo

        • Geralmente você deixa ela na sua Activity principal, que fica em execução o tempo todo (no meu caso o formulário que armazena a lista). Para passar para outras activities, você utiliza o método putExtra() da Intent que chama a Activity.

  • Marcos

    ola Rafael
    sou inexperiente com isso, me poderia por gentilezza fazer um exemplo porque ja tentei dessa ultima forma q vc sitou mas me da sempre erro de sintaxe, porque um array normal ele carrega mas dessa forma nao e com obejeto nao.

    obrigado
    Marcos Paulo

    • Tal artifício de passar parâmetros entre activities utilizando o método putExtra() é exemplificado nos tutoriais seguintes. Tente dar uma olhada no tutorial “Editando Registros no Banco de Dados”.

  • Samuel Rodrigues

    Olá, eu fiz tudo certo, pois não consegui adicionar os elementos na ListView, eu não consegui, por favor me ajude!

    • Olá Samuel! Não deu certo em que sentido? Qual erro está aparecendo? Tente copiar o log para encontrarmos em qual ponto o código está acusando problemas…

  • Marcos

    Ola Rafael

    Ola! estou com uma divida, como posso implementar a esse projeto um evento
    que me permite ao clicar no item a linha permanece colorido ate quando outro item nao for clicado, ja tentei com listSelector da ListView setando uma cor, mas nao deu certo, no android 3.2 isso e possível mas no android 2.3.3 ele pinta a listview inteira

    obrigado Agradeço desde Ja

  • Marcos

    Ola rafael,
    voce fez exemplo de como fazer para add imagens ao items ,q ja estao no projeto certo,
    como e possível carregar imagens que nao estao no projeto mas carregar elas por url.
    Agradeço desde Ja

  • karen

    Olá, no meu projeto preciso retornar uma lista de clientes. Só que em alguns casos preciso preencher um ListView com os nomes das cidades, em outros casos, os nomes dos cliente. Eu consigo ter mais de um método toString() na classe? Um retornando getNome e outro retornando getCidade?

  • Evandro

    Olá Rafael, estou desenvolvendo um projeto pessoal onde preciso utilizar
    uma lista de itens que ficará em uma segunda tela chamada pelo metodo
    chamaCadastro() ao clicar no botao Cadastro a partir da tela principal.
    No seu exemplo, você criou a lista como atributo na classe principal. A
    minha dúvida é como eu faço pra criar a lista dentro do metodo
    chamaCadastro() pra ela ser carregada só quando for acessada a tela de
    cadastro e não ao abrir?