Listview with different layouts per line, according to filtered value

Asked

Viewed 370 times

1

I have a unique table in BD, which contains the records with fields like: tipo, data, hora, cliente, historico

According to the value of tipo, the field cliente is or is not mandatory, that is to say, vazio.

To create a ListView I need to have the fields that she will display, but they will have cases that this field cliente, like others, they’ll all be empty.

Could I generate the records from ListView displaying fields specified by record according to their field tipo, so display only the necessary by type of record ?

Example:

If type = 1, displays fields:

  • TYPE - DATE - CUSTOMER

If type = 2, displays fields:

  • TYPE - HOUR - HISTORICAL
  • It seems to me that you may have a data modeling problem, because if you are two different pieces of information you would normally be in two different tables. But it’s hard to say with the limited information you have in the question.

  • It is basically the same type of record, only it varies some fields according to the field value tipo. So I want to hide or display the fields according to the type.

3 answers

6


Yes it is possible.

For this you must have/do:

  • A class that represents each item(Client) with "getters" for each of the values you want to show.
  • A custom Adapter.
  • A layout for each line type.

In the Adapter you have to overwrite the methods

public int getViewTypeCount()

and

public int getItemViewType(int position)

The first must return the number of views/layouts which will be created in getView(), the second type relating to view/layout to be created for the current line.

The method getView() Adapter must be implemented so that, depending on the value returned by getItemViewType(), create the layout to use and fill in your views according to the values in Arraylist(customers):

public class ClientesAdapter extends ArrayAdapter<Cliente> {

    private LayoutInflater inflater;
    private ArrayList<Cliente> Clientes;

    public ClientesAdapter(Context context, ArrayList<Cliente> clientes) {
        super(context, 0, clientes);
        this.clientes = clientes;
        inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    @Override
    public int getViewTypeCount() {
      return 2;
    }

    @Override
    public int getItemViewType(int position) {
      return clientes.get(position).getTipo();
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View v = convertView;
        int type = getItemViewType(position);

        if (v == null) {

            // Cria a view em função do tipo
            if (type == 1) {
                // Layout para o tipo 1
                v = inflater.inflate(R.layout.layout_tipo1, parent, false);
        }
        else {
            // Layout para o tipo 2
            v = inflater.inflate(R.layout.layout_tipo2, parent, false);
        }

        //O cliente para esta linha
        Cliente cliente = clientes.get(position);

        if (type == 1) {
         // atribuir aqui os valores às views do layout_tipo1
        }else{
            // atribuir aqui os valores às views do layout_tipo2
        }

        return v;
    }
}  

The Adapter is used like this:

ListView listView = (ListView) findViewById(R.id.clientes_list);
ArrayList<Clientes> clientes = getClientes(); 

ClientesAdapter clientesAdapter = new ClientesAdapter(this, clientes);
listView.setAdapter(clientesAdapter);

You will have to adapt according to your needs.

  • In Uma classe que represente cada item(Cliente) com "getters" para cada um dos valores que quer mostrar. It would be a class, in this case, that would search the records (query with the joins) and have the getters of all fields for Adapter to filter ?

  • It would be like the class of reply I gave this one question.

  • So she won’t be the one to get the records, she’ll be the adapter ?

  • No, it will be the one that receives the registration for a client. It will be used by Arraylist(Arraylist<Client>) which contains all the records.

  • private LayoutInflater inflater; e private ArrayList<Cliente> Clientes; would be within the class ?

  • Yes, I edited the answer.

  • can I open a chat ?

  • If you have any questions about how to implement a custom Arrayadapter(custom) see this video

  • I think the ctx here would be the context: inflater = (LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

  • Yes. Multi-sided Copy and Paste is what gives :)

  • Here ArrayList<Clientes> clientes = getClientes(); I think it would be ArrayList<Clientes> clientes = ArrayList<>();

  • Here inflater.inflate(R.layout.layout_tipo1, parent, false); instead of LayoutInflater.from(this.context).inflate(R.layout.item, null);. What would be the reason ? Different types ?

  • Not, getClientes() will be a method that will read the bank and return an Arraylist<Client>. I assume you already have a method of this type done.

  • Got it ! Now I understood why I was getting lost in a certain part. It was missing this part of looking for in the bank.

Show 9 more comments

2

In reality we just need to subscribe to the Arrayadapter getView method. Perhaps with this example it will be easier to control the views you want to display in a Listview via an Adapter array.

public class MyAdapter extends ArrayAdapter<MyObject>
{

    public MyAdapter(Context context, ArrayList<MyObject> myObjects){
        super(context, 0, myObjects);
    }

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

        if(convertView == null){
            convertView = LayoutInflater.from(getContext()).inflate(R.layout.my_list_item, parent, false);
        }

               //Recupera o Objecto da lista através do método getItem
        MyObject myObject = getItem(position);

                ((TextView) convertView).findViewById(R.id.text_view_one);

                ((TextView) convertView).findViewById(R.id.text_view_two);

               //Inteiro vindo da base de dados
              int tipo = myObject.getTipo();

                If(tipo == 1){
                    textView1.setText(....);

                    //Esconde a text view
                    textView2.setVisibility(View.GONE);
               }else{
                    textView1.setText(....);
                    textView2.setText(....);
           }
        return convertView;
    }
}
  • Fabio, select the whole code is press CTRL+K to format.

  • @wmsouza thank you...

  • 2

    "In reality we only need to subscribe to the getView method (..)" - This is true, however, in my reply I wanted to follow what the Basedapter class recommends for its implementation. Note that there are cases where determining the type of view to be used can give "more work", it being preferable to have a method for that purpose instead of putting this logic in the getView()

1

I needed an Adapter to provide me with the following: well, by my choice, set a specific layout for when I receive messages, or a specific layout for when I send the message. After a long time of cracking my head I had this insight:

package adapters;

import android.app.Activity;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.GradientDrawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import com.stevenilson.appchat.R;

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

import objetos.Message;

public class MessageAdapter extends BaseAdapter {

List<Message> messages = new ArrayList<Message>();
Context context;
public MessageAdapter(Context context) {
    this.context = context;
}
public void add(Message message) {
    this.messages.add(message);
    notifyDataSetChanged();
}
@Override
public int getCount() {
    return messages.size();
}
@Override
public Object getItem(int i) {
    return messages.get(i);
}
@Override
public long getItemId(int i) {
    return i;
}
@Override
public View getView(int i, View convertView, ViewGroup viewGroup) {
    MessageViewHolder holder = new MessageViewHolder();
    LayoutInflater messageInflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
    Message message = messages.get(i);
    if (message.isBelongsToCurrentUser()) {
        convertView = messageInflater.inflate(R.layout.my_message, null);
        holder.messageBody = (TextView) convertView.findViewById(R.id.message_body);
        convertView.setTag(holder);
        holder.messageBody.setText(message.getText());
    } else {
        convertView = messageInflater.inflate(R.layout.their_message, null);
        holder.avatar = (View) convertView.findViewById(R.id.avatar);
        holder.name = (TextView) convertView.findViewById(R.id.name);
        holder.messageBody = (TextView) convertView.findViewById(R.id.message_body);
        convertView.setTag(holder);
        holder.name.setText(message.getData().getName());
        holder.messageBody.setText(message.getText());
        GradientDrawable drawable = (GradientDrawable) holder.avatar.getBackground();
        drawable.setColor(Color.parseColor(message.getData().getColor()));
    }
    return convertView;
}
}

class MessageViewHolder {
    public View avatar;
    public TextView name;
    public TextView messageBody;
}

Using this Adapter together with a Message object for the other attributes:

package objetos;

import com.stevenilson.appchat.ChatMessage;

public class Message {
    private String text;
    private ChatMessage data;
    private boolean belongsToCurrentUser;
    public Message(String text, ChatMessage data, boolean belongsToCurrentUser) {
        this.text = text;
        this.data = data;
        this.belongsToCurrentUser = belongsToCurrentUser;
    }
    public String getText() {
        return text;
    }
    public ChatMessage getData() {
        return data;
    }
    public boolean isBelongsToCurrentUser() {
        return belongsToCurrentUser;
    }
}

With that I urge both in my main and in each method (sendMessage or receive) I was just changing the boolean belongsToCurrentUser for the Adapter to have control over what to do

sendMessage(View view){
    String texto = textMessage.getText().toString();


    belongsToCurrentUser = true;
    this.message.setText(texto);
    Message obMessage = new Message(texto, this.message, belongsToCurrentUser);


    if (texto.length() > 0) {

        messageAdapter.add(obMessage);
        this.message.setAction(ChatMessage.Action.SEND_ALL);
        this.message.setText(texto);
        this.socketTask.send(this.message);

    }

    listView.setSelection(listView.getCount() - 1);
}

I think that as late as it is, this answer may help someone.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.