androidandroid-recyclerviewandroid-adapterlayout-gravity

how to dynamically modify the recycler view's layout?


I write a chat application using Firebase.

In ChatActivity, there are a recycler view to display chatting information. The following image is the first loading is correct.

enter image description here

When enter the message send to others, the layout of some messages become different.

enter image description here

THE CODE in MessageAdapter

public MessageAdapter(List<YeMessage> mMessageList){
    this.mMsgList = mMessageList;

}

@Override
public MessageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(parent.getContext())
            .inflate(R.layout.item_message, parent, false);

    mContext = parent.getContext();
    ref = FirebaseDatabase.getInstance().getReference();

    return new MessageViewHolder(view);
}

public class MessageViewHolder extends RecyclerView.ViewHolder{
    @BindView(R.id.msg_message)
    TextView messageText;
    @BindView(R.id.msg_imageView)
    ImageView image;
    public MessageViewHolder(View view){
        super(view);
        ButterKnife.bind(this, view);
    }
}

@Override
public void onBindViewHolder(MessageViewHolder holder, int position) {

    mAuth = FirebaseAuth.getInstance();
    current_user_id = mAuth.getCurrentUser().getUid();

    YeMessage c = mMsgList.get(position);
    String from_user = c.getFrom();



    ref.child("Users").child(from_user).addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            RelativeLayout.LayoutParams rp_msg = (RelativeLayout.LayoutParams)holder.messageText.getLayoutParams();

            RelativeLayout.LayoutParams rp_img = (RelativeLayout.LayoutParams)holder.image.getLayoutParams();


            image = dataSnapshot.child("imageUrl").getValue().toString();
            if(from_user.equals(current_user_id)){

                //lp.gravity = Gravity.END;
                //end
                rp_img.addRule(RelativeLayout.ALIGN_PARENT_END);

                //rp_img.addRule(RelativeLayout.ALIGN_PARENT_TOP);
                holder.image.setLayoutParams(rp_img);
                //rp_msg.addRule(RelativeLayout.ALIGN_BOTTOM, R.id.msg_imageView);
                rp_msg.addRule(RelativeLayout.START_OF, R.id.msg_imageView);
                holder.messageText.setLayoutParams(rp_msg);
                Glide.with(mContext)
                        .load(image)
                        .into(holder.image);

            }else {
                //lp.gravity = Gravity.START;
                rp_img.addRule(RelativeLayout.ALIGN_PARENT_START);
                rp_img.addRule(RelativeLayout.ALIGN_PARENT_TOP);
                holder.image.setLayoutParams(rp_img);

                rp_msg.addRule(RelativeLayout.ALIGN_PARENT_TOP);
                rp_msg.addRule(RelativeLayout.END_OF, R.id.msg_imageView);
                holder.messageText.setLayoutParams(rp_msg);

                Glide.with(mContext)
                        .load(image)
                        .into(holder.image);
            }

        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

        }
    });


    YeMessage msg = mMsgList.get(position);
    holder.messageText.setText(msg.getMessage());

}

@Override
public int getItemCount() {
    return mMsgList.size();
}

I think the reason is that I have too little knowledge about the lifecycle of recycler view.

And I find if I want to change gravity in onBindViewHolder(), it can't be successful every time. Because it will be layout correctly when it calls the onCreateViewHolder().

How can to ensure that onCreateViewHolder() is called each time, so that finish to create layout programmatically?

Add item_message.xml

<?xml version="1.0" encoding="utf-8"?>
<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:id="@+id/message_single_item"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:orientation = "horizontal"
  android:padding="15dp">

<android.support.v7.widget.AppCompatImageView
    android:id="@+id/msg_imageView"
    android:layout_width="45sp"
    android:layout_height="45sp" />


<TextView
    android:id="@+id/msg_message"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/message_background"
    android:padding="10dp"
    android:textColor="#ffffff"
    />


</RelativeLayout>

Solution

  • I think you can have two different layouts for incoming and outgoing messages. It will be useful to you in future when you are changing the design.

    You can customize your RecyclerView according to your need. You can refer to http://www.codexpedia.com/android/android-recyclerview-with-multiple-different-layouts/ for a detailed answer.

    As far as your layout is concerned.

    For incoming messages-

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout 
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="horizontal" android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="10dp">
    
        <ImageView
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:background="#000000"/>
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" 
            android:text="askjjnads dma dm"
            android:layout_gravity="center"
            android:layout_marginLeft="10dp"
            android:layout_marginRight="20dp"
            />
    
    </LinearLayout>
    

    for out going messages-

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="horizontal" android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="end"
        android:padding="10dp">
    
    
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="askjjnads dma dm"
            android:layout_gravity="center"
            android:layout_marginLeft="20dp"
            android:layout_marginRight="10dp"
            />
    
        <ImageView
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:background="#000000"/>
    
    </LinearLayout>