sábado, 1 de agosto de 2015

Android – ListView com Interação de dados




Neste mês irei compartilhar uma dúvida que me surgiu no transcorrer do desenvolvimento de um projeto: como implementar o uso do componente ListView existindo uma interação de dados, melhor dizendo, como embutir um componente EditText dentro do ListView. Precisei deste recurso em meu projeto para criar uma tela de pesquisa de Produtos mais ágil, podendo interagir com o campo quantidade automaticamente. É importante lembrar que neste artigo terei como base o artigo “Android - Aprendendo a utilizar o ListView” do mês de Novembro de 2012 e mais outros pequenos trechos de códigos pesquisados na internet e modificados conforme a necessidade no momento.
Para quem nunca trabalhou com o componente “ListView” recomendo antes fazer uma leitura de nosso artigo citado acima, o qual aborda mais detalhadamente o funcionamento do mesmo.
Teremos também como base a implementação da classe “ArrayAdapter”, servindo para personalizar e montar o lay-out desejado.

Criando o Projeto

No primeiro momento deveremos inicializar um projeto Android padrão, clicando em “File/New/Android Application Project”, recomendo estar utilizando a versão “4” em diante. Este projeto irá conter os arquivos “MainActivity.java” e “activity_main.xml” (ambos criados automaticamente), até aqui não vimos nada de novo. Ver Imagem 01.

Figura 01: Exemplo Inicial.


Criando a Classe Produtos

Esta classe será responsável por atribuir e obter todos os produtos existentes. Iremos alimentá-la manualmente para facilitar o aprendizado (Ressalto que poderemos alimentá-la de qualquer fonte de dados).
Ver abaixo a Listagem 01 comentada.

package com.example.android_listviewinteracao;

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

Importaremos algumas bibliotecas, sendo a “java.util.ArrayList” e a “java.util.List” para utilizar o método ArrayList e List respectivamente, ambos para trabalhar com a classe “Produtos” mais adiante.

public class Produtos
{

     private static final long  
serialVersionUID = 1L;
     public int Id_Produto;
     public String Descricao;
     public Number Preco_Venda;
     public int Qtd;

Teremos os atributos Id_Produto (inteiro), Descricao (Texto), Preco_venda (Numérico) e Qtd (inteiro). Todos terão os métodos “Get” e “Set” implementados a seguir.         
    
     public Produtos()
     {
     }
    
No Construtor não colocaremos nenhuma codificação.

public int getId_Produto()
{
         return Id_Produto;
     }

public void setId_Produto(int id_produto)
{
         Id_Produto = id_produto;
     }
    
public String getDescricao()
{
         return Descricao;
     }

public void setDescricao(String descricao)
{
         Descricao = descricao;
     }
    
public Number getPreco_Venda()
{
         return Preco_Venda;
     }

public void setPreco_Venda(Number preco_Venda)
{
         Preco_Venda = preco_Venda;
     }

public int getQtd()
{
         return Qtd;
     }

public void setQtd(int qtd)
{
         Qtd = qtd;
     }
    
Já no método “ListarProdutos” iremos retornar dados do tipo “List<Produtos>”, ou seja, uma Lista de todos os produtos cadastrados. Veremos abaixo mais detalhadamente a inserção manual de alguns objetos nesta lista. Esta função irá nos servir para alimentar o ListView.

     public List<Produtos> ListarProdutos()
     {
List<Produtos> lista_produto = new ArrayList<Produtos>();
                  
         Produtos produto = new Produtos();
         produto.setId_Produto(1);
         produto.setDescricao("Arroz Prato Fino 5Kg");
         produto.setPreco_Venda(9.80);
         lista_produto.add(produto);
        
         Produtos produto2 = new Produtos();
         produto2.setId_Produto(2);
         produto2.setDescricao("Feijão Carioquinha 1 kg");
         produto2.setPreco_Venda(4.30);
         lista_produto.add(produto2);
        
         Produtos produto3 = new Produtos();
         produto3.setId_Produto(3);
produto3.setDescricao("Batata Elma Chips - Tamanho Família");
         produto3.setPreco_Venda(2.99);
         lista_produto.add(produto3);
        
         Produtos produto4 = new Produtos();
         produto4.setId_Produto(4);
         produto4.setDescricao("Macarrão Orsi Espaguete");
         produto4.setPreco_Venda(1.98);
         lista_produto.add(produto4);
        
         Produtos produto5 = new Produtos();
         produto5.setId_Produto(5);
         produto5.setDescricao("Azeite de Oliva 450 ml");
         produto5.setPreco_Venda(7.56);
         lista_produto.add(produto5);
        
         Produtos produto6 = new Produtos();
          produto6.setId_Produto(6);
produto6.setDescricao("Refrigerante Coca Cola 2 Litros Retornável");
         produto6.setPreco_Venda(3.80);
         lista_produto.add(produto6);
        
         Produtos produto7 = new Produtos();
         produto7.setId_Produto(7);
         produto7.setDescricao("Água Mineral 1,5 litros");
         produto7.setPreco_Venda(2.09);
         lista_produto.add(produto7);
        
                           
         return lista_produto;
     }
    
}
Listagem 01: Classe Produtos.

Criando o Lay-out do ListView “theclubadapter.xml”

Na Figura 02 teremos o lay-out proposto contendo os elementos: 3 componentes TextView, sendo “txtProd”, “txtId_Produto” e “txtPreco” servindo para listar a Descrição, Id e Preço de Venda do Produto. Teremos também um EditText “edtQtd” para atribuir a quantidade do Produto.

 
Figura 02: Lay-Out ListView.


Com base no lay-out criado anteriormente teremos o código XML correspondente na Listagem 02.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/LinearLayout01"
    android:layout_width="fill_parent"
    android:layout_height="90dip"
    android:gravity="right"
    android:orientation="vertical"
    android:paddingBottom="5dip"
    android:paddingTop="5dip"
    tools:ignore="InvalidId" >
    <LinearLayout
        android:id="@+id/linearLayout02"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:gravity="right"
        android:orientation="horizontal" >
        <LinearLayout
            android:id="@+id/LinearLayout03"
            android:layout_width="135dp"
            android:layout_height="84dp"
            android:layout_weight="0.99"
            android:orientation="vertical" >
            <TextView
               android:id="@+id/txtProduto"
            android:layout_width="match_parent"
            android:layout_height="30dp"
android:text="@string/txtprod"android:textAppearance="?android:attr/textAppearanceLarge" />
            <LinearLayout
                android:id="@+id/linearLayout06"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" >
                <TextView
                    android:id="@+id/txtId"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:gravity="top"
                    android:text="@string/id_"
android:textAppearance="?android:attr/textAppearanceSmall"
                    android:textSize="15dp"
                    android:typeface="sans" />
                <TextView
                    android:id="@+id/txtIdProduto"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:duplicateParentState="true"
                    android:text="@string/txtid_produto"
android:textAppearance=      "?android:attr/textAppearanceSmall"
                    android:textSize="15dp"
                    android:typeface="sans" />
            </LinearLayout>
            <LinearLayout
                android:id="@+id/linearLayout07"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" >
                <LinearLayout
                    android:id="@+id/linearLayout08"
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent" >
                    <TextView
                       android:id="@+id/txtp1"
                       android:layout_width="wrap_content"
                       android:layout_height="wrap_content"
                       android:gravity="top"
                       android:text="P1:"
android:textAppearance="?android:attr/textAppearanceSmall"
                       android:textSize="15dp"
                       android:typeface="sans" />
                    <TextView
                       android:id="@+id/txtPreco1"
                       android:layout_width="wrap_content"
                       android:layout_height="wrap_content"
                       android:duplicateParentState="true"
                       android:text="txtPreco1"
 android:textAppearance=     "?android:attr/textAppearanceSmall"
                       android:textSize="15dp"
                       android:typeface="sans" />
                    <TextView
                       android:id="@+id/txtEspaco1"
                       android:layout_width="wrap_content"
android:layout_height="wrap_content"
                       android:text="   "
                                            android:textAppearance="?android:attr/textAppearanceSmall" />
                </LinearLayout>
                <LinearLayout
                    android:id="@+id/linearLayout09"
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent" >
                    <TextView
                        android:id="@+id/txtEspaco2"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="    "
android:textAppearance="?android:attr/textAppearanceSmall" />
                </LinearLayout>
            </LinearLayout>
        </LinearLayout>
        <LinearLayout
            android:id="@+id/LinearLayout05"
            android:layout_width="82dp"
            android:layout_height="90dp"
            android:orientation="vertical" >
            <TextView
                android:id="@+id/txtQtd"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Qtd:"
android:textAppearance="?android:attr/textAppearanceMedium"
                android:textSize="20dp" />
            <EditText
                android:id="@+id/edtQuantidade"
                android:layout_width="79dp"
                android:layout_height="40dp"
                android:layout_margin="2dp"
                android:inputType="numberDecimal"
                android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceLarge"
                android:typeface="sans" >
            </EditText>
        </LinearLayout>
    </LinearLayout>
 </LinearLayout>
Listagem 02. Código XML do ListView.

Criando e Codificando a Activity “theclubadapter.java”

Na atividade “theclubadapter.java” iremos concentrar todo o comportamento do componente criado anteriormente. Iremos herdar da classe “ArrayAdapter” e sobrescreveremos o método “getView”, necessário para atribuirmos os dados. Ver Listagem 03 comentada.

package com.example.android_listviewinteracao;

import java.util.List;
import android.annotation.SuppressLint;
import android.content.Context;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.TextView;

Faremos o uso de algumas bibliotecas citadas no bloco de código acima.

public class theclubadapter extends ArrayAdapter<Produtos>
{

Como foi dito, esta classe irá herdar da classe ArrayAdapter, tendo como objeto “Produtos” (Classe criada para esta ocasião).

    private final LayoutInflater inflater;
    private final int resourceId;
    private List<Produtos> produtoitems;

O atributo do tipo “LayoutInflater” chamado “inflater” será responsável por “inflar” nosso listview com os dados do Contexto. Já o atributo inteiro “resourceId” receberá o próprio lay-out “theclubadaper”. Por último temos um List<Produtos>, variável responsável por armazenar todos os objetos do tipo Produto.
   
public theclubadapter(Context context, int resource, List<Produtos> produtos)
       {
           super(context, resource, produtos);
           this.inflater = LayoutInflater.from(context);
           this.resourceId = resource;
           this.produtoitems = produtos;
       }

Serão todos atribuídos no Construtor de nossa classe. Lembrando que com o método “super” estamos chamado o método de nossa classe pai. Antes de partirmos para os comentários referentes ao método “getView”, será necessário descrever a classe estática “ProdutosRepositorio” e mais outros dois métodos chamados “setupItem” e “setVal1TextChangeListener”.

     public static class ProdutosRepositorio
     {
        Produtos produtos;
       TextView txtProduto;
        TextView txtIdProduto;
        TextView txtPreco1;
        EditText edtQtd;
     }  

A classe pública estática “ProdutosRepositório” será composta por todos os membros do ListView mais a classe Produtos. Faremos o uso desta classe para ter um maior controle sobre a indexação dos registros localizados no ListView.

private void setupItem(ProdutosRepositorio repositorio)
        { 
             repositorio.txtProduto.setText(repositorio.produtos.Descricao);
              repositorio.txtIdProduto.setText(String.valueOf(repositorio.produtos.Id_Produto));
              repositorio.txtPreco1.setText(String.valueOf(repositorio.produtos.Preco_Venda));
              
             String Qtd = String.valueOf(repositorio.produtos.getQtd());
             if (Qtd.equals("0"))
                     repositorio.edtQtd.setText("");
             else
                     repositorio.edtQtd.setText(String.valueOf(repositorio.produtos.getQtd()));
     }

Neste método atribuimos todos os dados com origem da classe “ProdutosRepositorio”.

private void setVal1TextChangeListener(final ProdutosRepositorio repositorio)
     {
            repositorio.edtQtd.addTextChangedListener(new TextWatcher()
            {

               @Override
               public void beforeTextChanged(CharSequence s, int start,
  int count, int after)
        {
 
  }

               @Override
               public void onTextChanged(CharSequence s, int start,
               int before, int count)
               {
                  if(s.toString().length()>0)
     repositorio.produtos.setQtd(Integer.parseInt(s.toString());
               }

               @Override
               public void afterTextChanged(Editable s)
  {
               }
                                                     
            });
     }
}

No método “setVal1TextChangeListener” do componente EditText “Quantidade”, comparamos se o mesmo possui algum valor para logo em seguida alimentarmos com o valor corrente. Utilizamos para isto o método sobrescrito “OntextChanged”.
               
        @Override
        public View getView(int position, View convertView, ViewGroup parent)
        {          
         ProdutosRepositorio repositorio = null;

         convertView = inflater.inflate(resourceId, parent, false);
        
         repositorio = new ProdutosRepositorio();
         repositorio.produtos = produtoitems.get(position);
repositorio.txtProduto = (TextView)   convertView.findViewById(R.id.txtProduto);
repositorio.txtIdProduto = (TextView) convertView.findViewById(R.id.txtIdProduto);
repositorio.txtPreco1 = (TextView)  convertView.findViewById(R.id.txtPreco1);
repositorio.edtQtd = (EditText) convertView.findViewById(R.id.edtQuantidade);
           
         setVal1TextChangeListener(repositorio);
         convertView.setTag(repositorio);
         setupItem(repositorio);

         return convertView;
        }
        
Após uma abordagem da classe e das funções utilizadas, podemos finalizar com o método sobrescrito “getView”, o qual fará todo o trabalho “pesado” de nossa classe. Ele será invocado toda vez que atualizarmos nosso Listview, obtendo uma visão (view) para os dados na posição especificada no conjunto de dados. Importante salientar que podemos criar um modo de exibição manualmente ou inflá-lo a partir de um arquivo de layout XML. Teremos como parâmetro a variável “Position” para nos retornar um valor inteiro da posição do item do Listview, a “ConvertView” do tipo “View” para retornamos com as modificações necessárias e por fim a “ViewGroup” chamada “Parent” que será recuperada como parâmetro o tipo de “Layout”, por exemplo o “LinearLayout”.

1º Passo – Alimentaremos nossa “View” através do método já comentado “inflate”.
2º Passo - Vamos criar uma variável “repositorio” do tipo “ProdutosRepositorio” para atribuirmos todos os componentes utilizados.
3º Passo – Disparamos o método “setVal1TextChangeListener(repositorio)”.
4º Passo – Utilizamos o método “convertView.setTag(repositorio)” para salvar o “ProdutosReposito” como uma View.
5º Passo – Setamos os valores e retornamos a view para ser utilizada.


Criando o Lay-out “activity_main.xml”

Este será o “lay-out” principal, o qual irá fazer referência ao nosso “Listview” personalizado. Devemos inserir um ListView e um Button (o qual irá listar e carregar os produtos com quantidade maior que zero). Ver Imagem 03.

Figura 03: Lay-out principal.
               
O código XML é bem simples, podendo ser conferido na listagem 03.


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >
    <ListView
        android:id="@+id/listViewProdutos"
        android:layout_width="match_parent"
        android:layout_height="600dp" >
    </ListView>
    <Button
        android:id="@+id/btnConfirmar"
        android:layout_width="120dp"
        android:layout_height="50dp"
        android:onClick="Confirmar"
        android:text="Confirmar" />
</LinearLayout>
Listagem 03: Tela Principal.



Codificando a Activity “MainActivity.java”

Para entendermos um pouco mais, esta atividade ficará responsável por atribuir ao ListView o “theclubAdapter.xml” e alimentá-lo através da classe “Produtos.java”. Ao clicar no botão confirmar faremos uma varredura no mesmo para identificarmos os itens que possuem o valor maior que zero para o campo quantidade. Atribuiremos na classe “Produtos” com auxílio dos métodos “Sets” e em seguida disponibilizaremos através de uma Lista podendo ser obtidos através dos métodos “Gets”. (Neste caso poderíamos tanto utilizar estes dados nesta mesma Atividade quanto em uma outra qualquer passando o objeto por parâmetro).

package com.example.android_listviewinteracao;

import java.util.ArrayList;
import java.util.List;
import android.os.Bundle;
import android.app.Activity;
import android.app.AlertDialog;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;

Importaremos algumas bibliotecas necessárias para o bom funcionamento.

public class MainActivity extends Activity
{
    Button btnConfirmar;
    ListView listViewProdutos;
    ArrayAdapter<Produtos> adapter;

Teremos três variáveis, as duas primeiras são: uma do tipo “Button” e outra “ListView” (ambas fazem referências aos componentes visíveis em nosso XML). A variável “ArrayAdapter<Produtos>” irá armazenar toda a nossa classe personalizada.
   
      @Override
      protected void onCreate(Bundle savedInstanceState)
      {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            InicializaListeners();
            ListarTheClubAdapter();
      }

     
       public void InicializaListeners()
       {
listViewProdutos = (ListView)  findViewById(R.id.listViewProdutos);
            btnConfirmar = (Button)  findViewById(R.id.btnConfirmar);
       }
       
       public void ListarTheClubAdapter()
       {
           Produtos produtos = new Produtos();
           List<Produtos> lista_produtos = produtos.ListarProdutos();
adapter = new theclubadapter(this, R.layout.theclubadapter,   lista_produtos);
           listViewProdutos.setAdapter(adapter);
       }
No método “Oncreate” apenas inicializaremos nossos Componentes e através do “ListarTheClubAdapter” instanciaremos a classe “Produtos” para disparar o método “ListarProdutos”. A variável “adapter” irá receber a classe “theclubadapter” com os parâmetros de entrada: Contexto, tipo de layout e todos os dados em forma de lista.

       
       private void MensagemInformativa(String mensagen) {
                new AlertDialog.Builder(this)
                  .setTitle("The Club")
                  .setMessage(mensagen)
                  .setPositiveButton("OK", null)
                  .setCancelable(false)
                  .show();
              }
       
Achei mais didádico criar uma função chamada “MensagemInformativa” com o auxílio da classe “Builder” para informar ao usuário todos os registros com quantidade maior que zero.

       public void Confirmar(View view)
       {
ArrayList<Produtos> produtosporquantidade = new ArrayList<Produtos>();
                 
            for(int i=0;i<adapter.getCount();i++)
            {
                  int qtd = adapter.getItem(i).Qtd;
                  if (qtd > 0)
                  {
                   Produtos pro = new Produtos();
                   pro.setId_Produto(adapter.getItem(i).Id_Produto);
                   pro.setDescricao(adapter.getItem(i).Descricao);
                   pro.setPreco_Venda(adapter.getItem(i).Preco_Venda);
                   pro.setQtd(adapter.getItem(i).Qtd);
                   produtosporquantidade.add(pro);
                   }
            }
           
            for (int i = 0; i < produtosporquantidade.size(); i++)
            {    
MensagemInformativa("Id: "+ String.valueOf(produtosporquantidade.get(i).getId_Produto()) + " Descrição: "+ String.valueOf(produtosporquantidade.get(i).getDescricao()) + " Preço Venda: "+ String.valueOf(produtosporquantidade.get(i).getPreco_Venda()) + " Quantidade: "+ String.valueOf(produtosporquantidade.get(i).getQtd()));
            }
       }
}

Por fim o método “Confirmar” será disparado no evento “OnClick” do botão. Possuiremos duas etapas, sendo: um laço para alimentar nossa classe e o outro para carregar todos os dados atribuídos na mesma.

Teremos uma ideia geral de nosso aplicativo conferindo a Figura 04.

Figura 04: Exemplo funcionando.
 
Conclusões

Caros programadores, a ideia geral desta dica transformada em artigo foi de poder demonstrar como devemos proceder com o desenvolvimento de um componente específico para a plataforma Android, no nosso caso um ListView. O detalhe que não podemos esquecer é que este ListView poderá tanto “listar” informações de uma classe ou Banco de Dados quanto atribuir novos valores para o mesmo. Podemos utilizar exemplos deste tipo em um Pedido de Venda, agilizando no processo de escolha de um ou mais produtos. Poderíamos ter implementado também um “EditText” para o Preço de Venda sem muito trabalho. Fica aí a dica, um abraço e até o mês que vem!


Nenhum comentário:

Postar um comentário