I'm making a chat app and I'm having some trouble with the layout of my messages. I want the messages send by the logged in user to be aligned to the right of the layout and the messages send by other group members to be aligned to the left.
This is my xml file:
<android.support.constraint.ConstraintLayout
android:id="#+id/container_message"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp">
<ImageView
android:id="#+id/user_image"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginStart="8dp"
android:src="#color/colorBlack"
app:layout_constraintBottom_toBottomOf="#+id/container_message_text"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="#+id/date_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:fontFamily="#font/rubik_light"
android:text="19 juni, 00:32"
android:textSize="10sp"
app:layout_constraintStart_toStartOf="#+id/container_message_text"
app:layout_constraintTop_toBottomOf="#+id/container_message_text" />
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/container_message_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="48dp"
android:paddingStart="12dp"
android:paddingTop="12dp"
android:paddingEnd="12dp"
app:cardBackgroundColor="#color/colorTextWhite"
app:cardCornerRadius="16dp"
app:cardElevation="0dp"
app:layout_constraintStart_toStartOf="parent">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingStart="12dp"
android:paddingTop="7dp"
android:paddingEnd="12dp"
android:paddingBottom="7dp">
<TextView
android:id="#+id/message_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="#font/rubik"
android:textSize="16sp"
android:maxWidth="240dp" />
</FrameLayout>
</android.support.v7.widget.CardView>
Picture of the current layout:
I need the purple messages to be aligned to the right, how can this be done programmatically?
You should better try chat layout using two different layouts for sender's message and yours message and if you are using recyclerview then the following adapter might help you.
public class MessageListAdapter extends RecyclerView.Adapter {
private static final int VIEW_TYPE_MESSAGE_SENT = 1;
private static final int VIEW_TYPE_MESSAGE_RECEIVED = 2;
private Context mContext;
private List<UserMessage> mMessageList;
public MessageListAdapter(Context context, List<UserMessage> messageList) {
mContext = context;
mMessageList = messageList;
}
#Override
public int getItemCount() {
return mMessageList.size();
}
// Determines the appropriate ViewType according to the sender of the message.
#Override
public int getItemViewType(int position) {
UserMessage message = (UserMessage) mMessageList.get(position);
if (message.getSender().getUserId().equals(currentUserId)) {
// If the current user is the sender of the message
return VIEW_TYPE_MESSAGE_SENT;
} else {
// If some other user sent the message
return VIEW_TYPE_MESSAGE_RECEIVED;
}
}
// Inflates the appropriate layout according to the ViewType
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view;
if (viewType == VIEW_TYPE_MESSAGE_SENT) {
view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_message_sent, parent, false);
return new SentMessageHolder(view);
} else if (viewType == VIEW_TYPE_MESSAGE_RECEIVED) {
view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_message_received, parent, false);
return new ReceivedMessageHolder(view);
}
return null;
}
// Passes the message object to a ViewHolder so that the contents can be bound to UI.
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
UserMessage message = (UserMessage) mMessageList.get(position);
switch (holder.getItemViewType()) {
case VIEW_TYPE_MESSAGE_SENT:
((SentMessageHolder) holder).bind(message);
break;
case VIEW_TYPE_MESSAGE_RECEIVED:
((ReceivedMessageHolder) holder).bind(message);
}
}
private class SentMessageHolder extends RecyclerView.ViewHolder {
SentMessageHolder(View itemView) {
super(itemView);
//bind views
}
void bind(UserMessage message) {
//set values
}
}
private class ReceivedMessageHolder extends RecyclerView.ViewHolder {
ReceivedMessageHolder(View itemView) {
super(itemView);
//bind views
}
void bind(UserMessage message) {
//set values
}
}
}
Related
I am making an android chat app. I have a recyclerview to show messages. i have two different layouts for messages, one for sent and one for received. my recyclerview doesnt throw any error but is doesnt show anything on the screen.
This is my adapter class :
public class ChatAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<Chat> items;
private final int USER = 1, CONTACT = 2;
// Provide a suitable constructor (depends on the kind of dataset)
public ChatAdapter(List<Chat> items) {
this.items = items;
}
// Return the size of your dataset (invoked by the layout manager)
#Override
public int getItemCount() {
return this.items.size();
}
#Override
public int getItemViewType(int position) {
if(items.get(position).getType()==1)
return USER;
else
return CONTACT;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
RecyclerView.ViewHolder viewHolder;
LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext());
switch (viewType){
case USER:
View v1 = inflater.inflate(R.layout.chat_item_user, viewGroup, false);
viewHolder = new ViewHolder1(v1);
break;
default:
View v2 = inflater.inflate(R.layout.chat_item_contact, viewGroup, false);
viewHolder = new ViewHolder1(v2);
}
return viewHolder;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
switch (viewHolder.getItemViewType()) {
case USER:
ViewHolder1 vh1 = (ViewHolder1) viewHolder;
configureViewHolder1(vh1, position);
break;
default:
ViewHolder2 vh2 = (ViewHolder2) viewHolder;
configureViewHolder2(vh2, position);
break;
}
}
public void configureViewHolder1(ViewHolder1 viewHolder, int position){
Chat chat = items.get(position);
viewHolder.getTv().setText(chat.getMsg());
}
public void configureViewHolder2(ViewHolder2 viewHolder, int position){
Chat chat = items.get(position);
viewHolder.getTv().setText(chat.getMsg());
}
}
This is my Chat class:
public class Chat {
private int type;
private String msg;
private long time;
public Chat(int type,long time,String msg){this.type = type; this.msg = msg; this.time = time;}
public int getType(){return type;}
public void setType(int type){this.type = type;}
public String getMsg(){return msg;}
public void setMsg(String msg){this.msg = msg;}
public long getTime(){return time;}
public void setTime(long time){this.time = time;}
}
This my layout containing the recylcerview :
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ChatActivity">
<TextView
android:id="#+id/textView3"
android:layout_width="368dp"
android:layout_height="59dp"
android:layout_marginEnd="9dp"
android:layout_marginStart="7dp"
android:layout_marginTop="16dp"
android:background="#android:color/holo_green_light"
android:text="TextView"
android:textSize="30sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="368dp"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:layout_height="394dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/textView3" />
<EditText
android:id="#+id/editText8"
android:layout_width="325dp"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:layout_marginStart="8dp"
android:layout_marginTop="1dp"
android:ems="10"
android:inputType="textMultiLine"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/imageButton"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/recyclerView" />
<ImageButton
android:id="#+id/imageButton"
android:layout_width="53dp"
android:layout_height="54dp"
android:scaleType="fitCenter"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#+id/recyclerView"
app:srcCompat="#drawable/logo_arrow" />
These are my two layouts:
a. chat_item_contact
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/textView5"
android:layout_width="323dp"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_marginEnd="16dp"
android:layout_marginStart="45dp"
android:layout_marginTop="16dp"
android:background="#android:color/holo_green_light"
android:paddingLeft="10dp"
android:text="TextView"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
b. chat_item_user
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/textView4"
android:layout_width="329dp"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_marginEnd="48dp"
android:layout_marginStart="7dp"
android:layout_marginTop="7dp"
android:background="#android:color/holo_green_light"
android:paddingLeft="10dp"
android:text="TextView"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
I've done something similar, you should focus mostly on getItemViewType
Here is how I do (also I suggest you to use RecyclerView instead of ListView)
#Override
public int getItemViewType(int position){
if (/*your condition based on message received or sent*/) {
return VIEW_MESSAGE_RECEIVED;
}
else {
return VIEW_MESSAGE_SENT;
}
}
After, you just check what getItemViewType has returned
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == VIEW_MESSAGE_RECEIVED) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.chat_message_item_received, parent, false);
return new ChatAdapter.MyViewHolder(view);
}else {
View eventDataView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.chat_message_item_sent, parent, false);
return new ChatAdapter.MyViewHolder(view);
}
}
Try this code..
remove listitem null check because once value is assign after that it not getting null.
add also add one more things if one layout is show than other is gone at time two layout not show to good..
if (currentChat.getType() == 1) {
listItem1 = LayoutInflater.from(context).inflate(R.layout.chat_item_user, parent, false);
listItem1.setVisibility(View.VISIBLE);
listItem2.setVisibility(View.GONE);
} else {
listItem2 = LayoutInflater.from(context).inflate(R.layout.chat_item_contact, parent, false);
listItem2.setVisibility(View.VISIBLE);
listItem1.setVisibility(View.GONE);
}
I'm rather new to Android development and I'm trying to muddle my way through getting this working.
I tried scouring the web, but the tips I found were focused on making sure your getItemCount isn't returning 0, which it isn't, and making sure I attached the adapter to the RecyclerView, which I believe I have.
I'm hoping I'm just missing something dumb and this will be a quick fix, thanks in advance for any responses (and let me know if you need anymore info)!
Adapter:
public class MessageListAdapter extends RecyclerView.Adapter {
private static final int VIEW_TYPE_MESSAGE_SENT = 1;
private static final int VIEW_TYPE_MESSAGE_RECEIVED = 2;
private Context mContext;
private List<SocketMessage> mMessageList;
private String username;
public MessageListAdapter(Context context, List<SocketMessage> messageList, String username) {
mContext = context;
mMessageList = messageList;
this.username = username;
}
#Override
public int getItemCount() {
return mMessageList.size();
}
// Determines the appropriate ViewType according to the sender of the message.
#Override
public int getItemViewType(int position) {
SocketMessage message = (SocketMessage) mMessageList.get(position);
if (message.Username.contentEquals(this.username)) {
// If the current user is the sender of the message
return VIEW_TYPE_MESSAGE_SENT;
} else {
// If some other user sent the message
return VIEW_TYPE_MESSAGE_RECEIVED;
}
}
// Inflates the appropriate layout according to the ViewType.
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view;
if (viewType == VIEW_TYPE_MESSAGE_SENT) {
view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_message_sent, parent, false);
return new SentMessageHolder(view);
} else if (viewType == VIEW_TYPE_MESSAGE_RECEIVED) {
view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_message_received, parent, false);
return new ReceivedMessageHolder(view);
}
return null;
}
// Passes the message object to a ViewHolder so that the contents can be bound to UI.
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
SocketMessage message = (SocketMessage) mMessageList.get(position);
switch (holder.getItemViewType()) {
case VIEW_TYPE_MESSAGE_SENT:
((SentMessageHolder) holder).bind(message);
break;
case VIEW_TYPE_MESSAGE_RECEIVED:
((ReceivedMessageHolder) holder).bind(message);
}
}
public void add(SocketMessage socketMessage) {
mMessageList.add(socketMessage);
notifyDataSetChanged();
}
class MessageViewHolder {
public TextView name;
public TextView messageBody;
}
class ReceivedMessageHolder extends RecyclerView.ViewHolder {
TextView messageText, timeText, nameText;
ReceivedMessageHolder(View itemView) {
super(itemView);
messageText = (TextView) itemView.findViewById(R.id.text_message_body);
nameText = (TextView) itemView.findViewById(R.id.text_message_name);
}
void bind(SocketMessage message) {
messageText.setText(message.MessageText);
// Format the stored timestamp into a readable String using method.
nameText.setText(message.Username);
}
}
class SentMessageHolder extends RecyclerView.ViewHolder {
TextView messageText, timeText;
SentMessageHolder(View itemView) {
super(itemView);
messageText = (TextView) itemView.findViewById(R.id.text_message_body);
}
void bind(SocketMessage message) {
messageText.setText(message.MessageText);
}
}}
Activity OnCreate:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_socket_chat);
app = (HMCTHubApplication) getApplication();
socket = app.getSocket();
setContentView(R.layout.activity_socket_chat);
mMessageList = new ArrayList<SocketMessage>();
mMessageAdapter = new MessageListAdapter(this,mMessageList,app.getUsername());
messagesView = (RecyclerView) findViewById(R.id.reyclerview_message_list);
messagesView.setAdapter(mMessageAdapter);
messagesView.setLayoutManager(new LinearLayoutManager(this));
runOnUiThread(new Runnable() {
#Override
public void run() {
mMessageAdapter.add(new SocketMessage("test","this is a test msg"));
}
});
socket.on("receivedMessage",ReceivedMessage);
Button sendButton = (Button) findViewById(R.id.button_chatbox_send);
sendButton.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view){
EditText input = (EditText)findViewById(R.id.edittext_chatbox);
final SocketMessage message = new SocketMessage(app.getUsername(),input.getText().toString());
try{
socket.emit("ChatMessage", new ObjectMapper().writeValueAsString(message));
input.setText("");
runOnUiThread(new Runnable() {
#Override
public void run() {
mMessageAdapter.add(message);
}
});
}
catch(Exception ex){
Log.v("[ChatActivity]", "Fail on send message");
Log.v("[ChatActivity]",ex.getMessage());
}
}
});
}
Activity Layout:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="dotsoflight.hmcthub.SocketChatActivity">
<android.support.v7.widget.RecyclerView
android:id="#+id/reyclerview_message_list"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent">
</android.support.v7.widget.RecyclerView>
<!-- A horizontal line between the chatbox and RecyclerView -->
<View
android:layout_width="0dp"
android:layout_height="2dp"
android:background="#dfdfdf"
android:layout_marginBottom="0dp"
app:layout_constraintBottom_toTopOf="#+id/layout_chatbox"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
<LinearLayout
android:id="#+id/layout_chatbox"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:minHeight="48dp"
android:background="#ffffff"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent">
<EditText
android:id="#+id/edittext_chatbox"
android:hint="Enter message"
android:background="#android:color/transparent"
android:layout_gravity="center"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:maxLines="6"/>
<Button
android:id="#+id/button_chatbox_send"
android:text="SEND"
android:textSize="14dp"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:layout_width="64dp"
android:layout_height="48dp"
android:gravity="center"
android:layout_gravity="bottom" />
</LinearLayout>
</android.support.constraint.ConstraintLayout>
EDIT: I don't believe this question is related, as I'm calling this from an Activity not a fragment, I took a look at the answers but none seem to apply as they're using a fragment.
EDIT2: Levi found the problems! I had to set the LayoutManager prior to setting the Adapter and add the following to the bottom of my RecyclerView layout:
app:layout_constraintBottom_toBottomOf="parent"
As I was telling it to fit the height constraint while not setting a bottom constraint.
Set the adapter AFTER the layout manager:
messagesView.setLayoutManager(new LinearLayoutManager(this));
messagesView.setAdapter(mMessageAdapter);
EDIT:
There's no constraint to the bottom of your recycler view, but you set the height to match constraint. You need to constraint both top and bottom to something in this case:
app:layout_constraintBottom_toBottomOf="parent"
That is when the sender from one device sends message,it should appear on the right hand side and when the other device gets the message it should appear on the left hand side.
My java class: This is the function I am calling
private void chatRowStyling(boolean isItMe, ViewHolder holder){
if (isItMe){
holder.layoutParams.gravity = Gravity.END;
holder.chatBody.setTextColor(Color.BLUE);
holder.senderName.setBackgroundResource(R.drawable.speech_bubble_green);
}else{
holder.layoutParams.gravity = Gravity.START;
holder.chatBody.setTextColor(Color.GREEN);
holder.senderName.setBackgroundResource(R.drawable.speech_bubble_orange);
}
Log.i("TAG","error :" + mySnapShot);
holder.senderName.setLayoutParams(holder.layoutParams);
holder.chatBody.setLayoutParams(holder.layoutParams);
}
In the Screenshot, all the messages appear on the right side, whereas I want one to be on right and another to be on left from different users.
This is my XML code :
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/singleMessageContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="#+id/author"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:paddingLeft="12dp"
android:paddingRight="12dp"
android:text="#string/sender"
android:textColor="#2980b9"
android:textSize="16sp"
android:textStyle="bold" />
<TextView
android:id="#+id/message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:layout_margin="5dip"
android:padding="12dp"
android:text="#string/author"
android:textColor="#2c3e50" />
</LinearLayout>
The best way to do it would be to implement RecyclerView with separate view types, that way you could adjust layout however you want without some shady workaround. Here is example to do it.
Reference : How to create RecyclerView with multiple view type?
EDIT:
Convinced by comments I decided to add some more explanation.
You could create two separate layouts, one for your messages:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/tvAuthor"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"/>
<TextView
android:id="#+id/tvMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/tvAuthor"
android:layout_alignParentRight="true"/>
</RelativeLayout>
and the other one for messages from friend:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/tvAuthor"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/tvMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/tvAuthor" />
</RelativeLayout>
Then you can create a class for your messages:
public class Message {
private String message;
private String author;
public Message(String message, String author) {
this.message = message;
this.author = author;
}
public String getMessage() {
return message;
}
public String getAuthor() {
return author;
}
}
Next step would be to create adapter for your RecyclerView that will use two seperate ViewHolders, one for your messages and the other for messages from your friend. Inside OnCreateViewHolder you can choose which layout you want to display for each message. Then in OnBindViewHolder, you can fill TextViews with correct message data.
public class MessageAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private ArrayList<Message> messages;
private final static int TYPE_FROM_FRIEND = 1;
private final static int TYPE_TO_FRIEND = 2;
public MessageAdapter(ArrayList<Message> messages) {
this.messages = messages;
}
public int getItemViewType(int position) {
if (messages.get(position).getAuthor().equals("Me")) {
return TYPE_TO_FRIEND;
} else {
return TYPE_FROM_FRIEND;
}
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
int layout = 0;
RecyclerView.ViewHolder viewHolder;
switch (viewType){
case TYPE_TO_FRIEND:
layout = R.layout.view_message_to_friend;
View toFriendView = LayoutInflater
.from(parent.getContext())
.inflate(layout, parent, false);
viewHolder=new ToFriendViewHolder(toFriendView);
break;
case TYPE_FROM_FRIEND:
layout = R.layout.view_message_from_friend;
View fromFriendView = LayoutInflater
.from(parent.getContext())
.inflate(layout, parent, false);
viewHolder = new FromFriendViewHolder(fromFriendView);
break;
default:
viewHolder = null;
break;
}
return viewHolder;
}
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
int viewType=holder.getItemViewType();
switch (viewType){
case TYPE_TO_FRIEND:
((ToFriendViewHolder)holder).tvMessage.setText(messages.get(position).getMessage());
((ToFriendViewHolder)holder).tvAuthor.setText(messages.get(position).getAuthor());
break;
case TYPE_FROM_FRIEND:
((FromFriendViewHolder)holder).tvMessage.setText(messages.get(position).getMessage());
((FromFriendViewHolder)holder).tvAuthor.setText(messages.get(position).getAuthor());
break;
}
}
private class ToFriendViewHolder extends RecyclerView.ViewHolder {
private TextView tvAuthor;
private TextView tvMessage;
public ToFriendViewHolder(View view) {
super(view);
tvAuthor = (TextView) view.findViewById(R.id.tvAuthor);
tvMessage = (TextView) view.findViewById(R.id.tvMessage);
}
}
private class FromFriendViewHolder extends RecyclerView.ViewHolder {
private TextView tvAuthor;
private TextView tvMessage;
public FromFriendViewHolder(View view) {
super(view);
tvAuthor = (TextView) view.findViewById(R.id.tvAuthor);
tvMessage = (TextView) view.findViewById(R.id.tvMessage);
}
}
#Override
public int getItemCount() {
return messages.size();
}
}
Finally you can set RecyclerView's adapter in your activity:
public class MainActivity extends AppCompatActivity {
private RecyclerView rvMain;
private ArrayList<Message> messages = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
rvMain = (RecyclerView) findViewById(R.id.rvMain);
rvMain.setLayoutManager(new LinearLayoutManager(this));
messages.add(new Message("Hello", "Me"));
messages.add(new Message("Hi", "Friend"));
messages.add(new Message("How are you?", "Me"));
messages.add(new Message("I'm fine and you?", "Friend"));
MessageAdapter adapter = new MessageAdapter(messages);
rvMain.setAdapter(adapter);
}
}
You can achieve it by setting the view gravity not the LayoutParams with something like this:
if(isIfMe) {
holder.linearLayout.setGravity(Gravity.END);
holder.tvAuthor.setGravity(Gravity.END);
} else {
holder.linearLayout.setGravity(Gravity.END);
holder.tvAuthor.setGravity(Gravity.END);
}
I just started an new app (an easy chat app) on Android and Im kind of stuck in the recyclerView. I am switching between 2 XML files to display a message either on the left or on the right of the screen. The messages on the left work fine, but the messages which should be displayed on the right jump to the left when debugging the app. In the original XML they are connected to the right with constraints.
Here is the code of the xml file of the message on the right:
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/textViewMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="16dp"
android:layout_marginTop="8dp"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1.0"
tools:text="Hi, sub?" />
</android.support.constraint.ConstraintLayout>
And the code from the adapter
public class ChatAdapter extends RecyclerView.Adapter{
private final Context mContext;
private final static int showLeft = 1;
private final static int showRight = 0;
public ChatAdapter(#NonNull Context context) {
mContext = context;
}
#Override
public NumberViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
int layoutId;
switch(viewType){
case showLeft:
layoutId = R.layout.message_received;
Log.d("Inflation: ", "left");
break;
case showRight:
layoutId = R.layout.message_sent;
Log.d("Inflation: ", "right");
break;
default:
throw new IllegalArgumentException("Invalid view type, value of " + viewType);
}
View view = LayoutInflater.from(mContext).inflate(layoutId, parent, false);
view.setFocusable(true);
return new NumberViewHolder(view);
}
#Override
public void onBindViewHolder(NumberViewHolder holder, int position) {
holder.message.setText(DataHandling.ChatMessages.get(position));
}
#Override
public int getItemCount() {
return DataHandling.ChatMessages.size();
}
#Override
public int getItemViewType(int position) {
if(DataHandling.MessageState.get(position) == 1){
return showRight; //If the message was received
}else{
return showLeft;
}
}
public class NumberViewHolder extends RecyclerView.ViewHolder{
TextView message;
public NumberViewHolder(View itemView) {
super(itemView);
message = (TextView) itemView.findViewById(R.id.textViewMessage);
}
}
How can I make them stick to the right side of the screen?
try the below, I basically replaced the Constraint Layout with Relative Layout and given layout_alignParentRight to true. this should work.
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/textViewMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="8dp"
android:textSize="16sp"
android:layout_alignParentRight="true"
tools:text="Hi, sub?" />
</RelativeLayout>
I made the FriendlyChat using firebase
However all the texts are appearing in same line, both from sender and receiver!
I want to apply chat bubbles with left and right alignment but have no idea where to start
I also want to wrap the text view inside chat bubble images? but i have no idea how to do that?
any help!
public class MessageAdapter extends ArrayAdapter<FriendlyMessage> {
public MessageAdapter(Context context, int resource, List<FriendlyMessage> objects) {
super(context, resource, objects);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = ((Activity) getContext()).getLayoutInflater().inflate(R.layout.item_message, parent, false);
}
ImageView photoImageView = (ImageView) convertView.findViewById(R.id.photoImageView);
TextView messageTextView = (TextView) convertView.findViewById(R.id.messageTextView);
TextView authorTextView = (TextView) convertView.findViewById(R.id.nameTextView);
FriendlyMessage message = getItem(position);
boolean isPhoto = message.getPhotoUrl() != null;
if (isPhoto) {
messageTextView.setVisibility(View.GONE);
photoImageView.setVisibility(View.VISIBLE);
Glide.with(photoImageView.getContext())
.load(message.getPhotoUrl())
.into(photoImageView);
} else {
messageTextView.setVisibility(View.VISIBLE);
photoImageView.setVisibility(View.GONE);
messageTextView.setText(message.getText());
}
authorTextView.setText(message.getName());
return convertView;
}
}
item_message.xml
<?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/lp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="#dimen/activity_horizontal_margin"
android:layout_marginStart="#dimen/activity_horizontal_margin"
android:orientation="vertical">
<ImageView
android:id="#+id/photoImageView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true" />
<TextView
android:id="#+id/messageTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="0"
android:background="#drawable/messenger_bubble_large_white"
android:padding="2dp"
android:textAppearance="?android:attr/textAppearanceLarge"
tools:text="Message" />
<TextView
android:id="#+id/nameTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0"
android:textAppearance="?android:attr/textAppearanceSmall"
tools:text="Name" />
</LinearLayout>
Hi #Parjanya you have have to check type and based upon condition yo can hide one and show other
for me I used 2 different viewHolder and 2 different xml. My code is below;
MessageChatAdapter.java;
public class MessageChatAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<ChatMessage> mChatList;
public static final int SENDER = 0;
public static final int RECIPIENT = 1;
public MessageChatAdapter(List<ChatMessage> listOfFireChats) {
mChatList = listOfFireChats;
}
#Override
public int getItemViewType(int position) {
if (mChatList.get(position).getRecipientOrSenderStatus() == SENDER) {
return SENDER;
} else {
return RECIPIENT;
}
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
RecyclerView.ViewHolder viewHolder;
LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext());
switch (viewType) {
case SENDER:
View viewSender = inflater.inflate(R.layout.layout_sender_message, viewGroup, false);
viewHolder = new ViewHolderSender(viewSender);
break;
case RECIPIENT:
View viewRecipient = inflater.inflate(R.layout.layout_recipient_message, viewGroup, false);
viewHolder = new ViewHolderRecipient(viewRecipient);
break;
default:
View viewSenderDefault = inflater.inflate(R.layout.layout_sender_message, viewGroup, false);
viewHolder = new ViewHolderSender(viewSenderDefault);
break;
}
return viewHolder;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
switch (viewHolder.getItemViewType()) {
case SENDER:
ViewHolderSender viewHolderSender = (ViewHolderSender) viewHolder;
configureSenderView(viewHolderSender, position);
break;
case RECIPIENT:
ViewHolderRecipient viewHolderRecipient = (ViewHolderRecipient) viewHolder;
configureRecipientView(viewHolderRecipient, position);
break;
}
}
private void configureSenderView(ViewHolderSender viewHolderSender, int position) {
ChatMessage senderFireMessage = mChatList.get(position);
viewHolderSender.getSenderMessageTextView().setText(senderFireMessage.getMessage());
viewHolderSender.getmTimeStamp().setText(converteTimestamp(senderFireMessage.getTimestap()));
}
private void configureRecipientView(ViewHolderRecipient viewHolderRecipient, int position) {
ChatMessage recipientFireMessage = mChatList.get(position);
viewHolderRecipient.getRecipientMessageTextView().setText(recipientFireMessage.getMessage());
viewHolderRecipient.getmTimeStamp().setText(converteTimestamp(recipientFireMessage.getTimestap()));
}
/*==============ViewHolder===========*/
/*ViewHolder for Sender*/
public class ViewHolderSender extends RecyclerView.ViewHolder {
private TextView mSenderMessageTextView;
private TextView mTimeStamp;
public ViewHolderSender(View itemView) {
super(itemView);
mSenderMessageTextView = (TextView) itemView.findViewById(R.id.text_view_sender_message);
mTimeStamp = (TextView) itemView.findViewById(R.id.textView2);
}
public TextView getSenderMessageTextView() {
return mSenderMessageTextView;
}
public TextView getmTimeStamp() {
return mTimeStamp;
}
}
/*ViewHolder for Recipient*/
public class ViewHolderRecipient extends RecyclerView.ViewHolder {
private TextView mRecipientMessageTextView;
private TextView mTimeStamp;
public ViewHolderRecipient(View itemView) {
super(itemView);
mRecipientMessageTextView = (TextView) itemView.findViewById(R.id.text_view_recipient_message);
mTimeStamp = (TextView) itemView.findViewById(R.id.textView2);
}
public TextView getRecipientMessageTextView() {
return mRecipientMessageTextView;
}
public TextView getmTimeStamp() {
return mTimeStamp;
}
}
layout_sender_message.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/text_view_sender_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="I am doing ok"
android:padding="8dp"
android:layout_marginRight="10dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="2dp"
android:textStyle="bold"
android:textSize="14sp"
android:textColor="#FFFFFF"
android:background="#drawable/sender_rounded_corners"
android:layout_alignParentRight="true" />
<TextView
android:id="#+id/textView2"
android:layout_width="60dp"
android:layout_height="wrap_content"
android:layout_alignBottom="#+id/text_view_sender_message"
android:layout_gravity="bottom"
android:layout_toLeftOf="#id/text_view_sender_message"
android:text="TextView"
android:textSize="12sp"
android:textStyle="italic"/>
</RelativeLayout>
layout_recipient_message.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:orientation="horizontal"
android:layout_height="wrap_content">
<TextView
android:id="#+id/text_view_recipient_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="Hi. How are you?"
android:padding="8dp"
android:textStyle="bold"
android:layout_marginRight="10dp"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="2dp"
android:textColor="#727272"
android:textSize="15sp"
android:background="#drawable/recipient_rounded_corners"/>
<TextView
android:id="#+id/textView2"
android:layout_width="69dp"
android:layout_height="wrap_content"
android:layout_toRightOf="#+id/text_view_recipient_message"
android:text="TextView"
android:textSize="12sp"
android:layout_gravity="bottom"
android:textStyle="italic"/>
</LinearLayout>
Pretty basic and needs to be fixed but this will give you a headstart.
I think you should use two different custom components for chat left and right bubbles.
Set as a background of TextView and make the boolean condition for show and hide two chat bubbles.
If you want more information and demo with use of firebase then please check below link:
https://www.androidtutorialpoint.com/firebase/real-time-android-chat-application-using-firebase-tutorial/
I hope it helps you.
Thank you:)
Just two words Answer...
Use Gravity
eg
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) _chat_view.getLayoutParams();
lp.gravity = Gravity.END | Gravity.RIGHT;
_chat_view.setLayoutParams(lp);
where _chat_view is your Message (LinearLayout) container.