3

My Recyclerview is a list of messages.

Each item is a linearlayout with a wrap_content width.

The problem is that when a new item is inserted, the item would take the previous item's width if it's bigger (Which makes it look like it has a big padding)

I tried setRecycable(false) in ViewHolder constructor but that caused some problems and I want to use a different approach.

Any help is appreciated. Thanks

EDIT: Layout:

<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="wrap_content"
android:orientation="vertical">

<include
    android:id="@+id/message_date_layout"
    layout="@layout/time_bubble"/>

<LinearLayout
    android:id="@+id/message_container"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_margin="4dp"
    android:layout_marginEnd="30dp"
    android:layout_marginLeft="6dp"
    android:layout_marginRight="30dp"
    android:layout_marginStart="6dp"
    android:background="@drawable/background_incoming_chat_bubble"
    android:orientation="vertical"
    android:padding="6dp">
//other views
 </LinearLayout>
</LinearLayout>

CraeteViewHolder

  @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        ChatMessagesAdapter.ViewHolder viewHolder;
        LayoutInflater inflater = LayoutInflater.from(context);
        View v = null;
        switch (viewType) {
            case OUTGOING:
                v = inflater.inflate(R.layout.chat_bubble_outgoing, parent, false);
                break;
            case INCOMING:
                v = inflater.inflate(R.layout.chat_bubble_incoming, parent, false);
                break;
        }
        viewHolder = new ChatMessagesAdapter.ViewHolder(v);
        return viewHolder;
    }
Roudi
  • 1,249
  • 2
  • 12
  • 26
  • Please add some code. – sharp Feb 15 '17 at 10:24
  • @FiN edited the original post – Roudi Feb 15 '17 at 10:30
  • could you share `chat_bubble_outgoing` and `chat_bubble_incoming` layouts? – sharp Feb 15 '17 at 10:32
  • I only have problem with the incoming layout. And that's the layout i posted above the onCreateViewHolder. It's basically just like i posted. The Linearlayout with the id "message_container" is the one that is acting weird. I'll update the code to the full layout – Roudi Feb 15 '17 at 10:35
  • Did you find any solution? I'm facing a similar problem. – David Miguel Apr 24 '17 at 12:34
  • @DavidMiguel Hey, I ended up using setIsRecyclable(false); in the ViewHolder constructor after calling super. If you found a better solution, please let me know. – Roudi Apr 25 '17 at 13:07
  • @PampaZiya check this answer https://stackoverflow.com/a/39735385/4606266 It works for me for now. And I have to say that setIsRecyclable(false); is too much expensive for performance issue. I wouldn't use it – ziLk Jul 30 '17 at 15:05

3 Answers3

3

Can you try this in your Adapter

      @Override
      public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
            holder.itemView.requestLayout();
      }

maybe this will force the layout to recalculate its dimensions

Mohammad Ersan
  • 12,304
  • 8
  • 54
  • 77
  • what does loose performance mean? this one is working for me. Although I didn't do it to my itemview but to a view inside the itemview. – Community Jan 31 '19 at 02:53
0

update your above with this

 @Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    ChatMessagesAdapter.ViewHolder viewHolder;
    LayoutInflater inflater = LayoutInflater.from(context);
    View v = null;
    switch (viewType) {
        case OUTGOING:
            v = inflater.inflate(R.layout.chat_bubble_outgoing, null, false);
            break;
        case INCOMING:
            v = inflater.inflate(R.layout.chat_bubble_incoming, null, false);
            break;
    }
    viewHolder = new ChatMessagesAdapter.ViewHolder(v);
    return viewHolder;
}

and also use the holder.setIsRecyclable(false); in end line of onBindViewHolder.

Ankush Bist
  • 1,862
  • 1
  • 15
  • 32
  • Hello, I tried the above. This caused a problem when using this: notifyItemChanged(0); That item becomes changes but the old copy of it is diplayed on top of it, floating. Weird – Roudi Feb 15 '17 at 10:52
  • remove holder.setIsRecyclable(false); and update what changes you found. – Ankush Bist Feb 15 '17 at 10:55
  • No changes when the setIsRecycable is true. The layouts still take the widths of the previous item – Roudi Feb 15 '17 at 10:57
  • can your layout image. and full code for the xml layout. – Ankush Bist Feb 15 '17 at 10:58
0

This might help you

        @Override
        public int getItemViewType(int position) {
            if (datas.get(position).getType() == Utils.OUTGOING) {
                return Utils.OUTGOING;
            } else {
                return Utils.INCOMING;
            }
        }

        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view;
            switch (viewType) {
                case Utils.OUTGOING:
                    view = LayoutInflater.from(parent.getContext()).inflate(R.layout.chat_bubble_outgoing, parent, false);
                    return new OUTGOINGHolder(view);
                case Utils.INCOMING:
                    view = LayoutInflater.from(parent.getContext()).inflate(R.layout.chat_bubble_incoming, parent, false);
                    return new INCOMINGHolder(view);
            }
            return null;
        }
Piyush Patel
  • 371
  • 1
  • 5
  • 13