Mardaunt
Mardaunt

Reputation: 92

How to use different layouts for incoming & outgoing chat messages

I have a design for messages. 2 xml files are responsible for the design:

recyclerview_item_incoming.xml
recyclerview_item_outgoing.xml

It looks like this:

enter image description here

Messages are stored inside the RecyclerView. RecyclerView is connected to SQLite via LiveData -> Room. More Info

To work with the RecyclerView I have 2 classes:

MessageListAdapter:

package com.mardaunt.telesupp.recyclerview;

import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.ListAdapter;

import com.mardaunt.telesupp.room.Message;

public class MessageListAdapter extends ListAdapter<Message, MessageViewHolder> {

    public static int idMessage = 0; // I added that
    public static int countMessages = 0; // I added that

    public MessageListAdapter(@NonNull DiffUtil.ItemCallback<Message> diffCallback) {
        super(diffCallback);
    }

    @Override
    public MessageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        countMessages = getItemCount();
        //System.out.println(countMessages + " - This countMessages\n" + idMessage + "- This idMessage; " + viewType + " - viewType");
        System.out.println(idMessage);
        //if(idMessage >= countMessages) idMessage = 0;
        // I need to pass the create index method of the current message.!!!!!!!!!!
        // The getItem() function returns a Message object.
        return MessageViewHolder.create(parent, getItem(idMessage));
    }

    @Override
    public void onBindViewHolder(MessageViewHolder holder, int position) {
        Message current = getItem(position);
        //System.out.println(current.getId() + " " + current.getPhone() + " " + current.getText());
        holder.bind(current.getPhone() ,current.getText()); // Бинтим только тело телефон и сообщение!
        idMessage = position+1;
        if(idMessage >= countMessages) idMessage = 0;
    }

    public static class MessageDiff extends DiffUtil.ItemCallback<Message> {

        @Override
        public boolean areItemsTheSame(@NonNull Message oldItem, @NonNull Message newItem) {
            return oldItem == newItem;
        }

        @Override
        public boolean areContentsTheSame(@NonNull Message oldItem, @NonNull Message newItem) {
            return oldItem.getText().equals(newItem.getText());
        }
    }
}

MessageViewHolder:

package com.mardaunt.telesupp.recyclerview;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.recyclerview.widget.RecyclerView;

import com.mardaunt.telesupp.R;
import com.mardaunt.telesupp.room.Message;

class MessageViewHolder extends RecyclerView.ViewHolder {
    private final TextView phoneItemView;
    private final TextView messageItemView;

    private MessageViewHolder(View itemView) {
        super(itemView);
        messageItemView = itemView.findViewById(R.id.text_view_message);
        phoneItemView = itemView.findViewById(R.id.text_view_phone);
    }

    public void bind(String phone, String message) {
        phoneItemView.setText(phone);
        messageItemView.setText(message);
    }

        //The method decides which design to choose for the message bubble.
    static MessageViewHolder create(ViewGroup parent, Message current) {
        View view;
        if (current.getNature().equals("outgoing"))
            view = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.recyclerview_item_outgoing, parent, false);
        else view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.recyclerview_item_incoming, parent, false);
        return new MessageViewHolder(view);
    }
}

And Message:

package com.mardaunt.telesupp.room;

import androidx.annotation.NonNull;
import androidx.room.Entity;
import androidx.room.PrimaryKey;

@Entity(tableName = "messages_table")
public class Message {

    @PrimaryKey(autoGenerate = true)
    private int id;
    private String phone;
    private String text;
    private String nature;

    public Message(int id,
                   @NonNull String phone,
                   @NonNull String text,
                   @NonNull String nature
                    ) {
        this.id = id;
        this.phone = phone;
        this.text = text;
        this.nature = nature; // incoming OR outgoing
    }

    public int getId(){return this.id;}
    public String getPhone(){return this.phone;}
    public String getText(){return this.text;}
    public String getNature(){return this.nature;}
}

Problem: I want the incoming messages to be located on the left. And outgoing messages are located on the right. To do this, I slightly changed the static method of the MessageViewHolder class:

 //The method decides which design to choose for the message bubble.
static MessageViewHolder create(ViewGroup parent, Message current) {
    View view;
    if (current.getNature().equals("outgoing"))
        view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.recyclerview_item_outgoing, parent, false);
    else view = LayoutInflater.from(parent.getContext())
            .inflate(R.layout.recyclerview_item_incoming, parent, false);
    return new MessageViewHolder(view);
}

But the problem is that I do not know how I can correctly pass the Message objects to this method? As you can see, I tried to pass the Message object in the MessageListAdapter class:

@Override
public MessageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    countMessages = getItemCount();
    // I need to pass the create index method of the current message.!!!!!!!!!!
    // The getItem() function returns a Message object.
    return MessageViewHolder.create(parent, getItem(idMessage));
}

@Override
public void onBindViewHolder(MessageViewHolder holder, int position) {
    Message current = getItem(position);
    holder.bind(current.getPhone() ,current.getText()); // Бинтим только тело телефон и сообщение!
    idMessage = position+1;
    if(idMessage >= countMessages) idMessage = 0;
}

I added 2 static variable (idMessage, countMessages), but this worked don't correctly. How I can add Message object for method MessageViewHolder.create(...) ?

Project on GitHub: https://github.com/MinorityMeaning/HelloApp

Upvotes: 1

Views: 440

Answers (1)

Zain
Zain

Reputation: 40810

The getItemViewType() is the right place for determining the item layout. So you need to move the logic there, so override it in the adapter:

@Override
public int getItemViewType(int position) {
    if (getItem(position).getNature().equals("outgoing"))
        return R.layout.recyclerview_item_outgoing;
    else
        return R.layout.recyclerview_item_incoming;
}

And that being reflected in the viewType parameter of onCreateViewHolder(), so it holds the right layout for the current item. So you'd pass that to the ViewHolder:

@Override
public MessageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    return MessageViewHolder.create(parent, viewType);
}

And In ViewHolder set that as your layout:

static MessageViewHolder create(ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(parent.getContext())
            .inflate(viewType, parent, false);
    return new MessageViewHolder(view);
}

Upvotes: 3

Related Questions