Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RecyclerView item layout_weight, sizes not updating

I have two text views side by side in my RecyclerView item. One of the views has layout_weight="1" to keep another view visible if the view is wide.

The problem is that the the view sizes are not updating when the views got recycled, so to textView id:name width is not correct when i scroll the list.

Should I somehow force the view to update the layout?

My RecyclerView item:

<LinearLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginLeft="16dp"
    android:gravity="center_vertical"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/name"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginRight="8dp"
        android:layout_weight="1"
        android:ellipsize="end"
        android:maxLines="1" />

    <LinearLayout
        android:id="@+id/code_container"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:background="@drawable/background_code"
        android:orientation="vertical">

        <TextView
            android:id="@+id/code"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ellipsize="end"
            android:paddingBottom="1dp"
            android:paddingLeft="7dp"
            android:paddingRight="7dp"
            android:paddingTop="1dp"
            android:singleLine="true"/>

    </LinearLayout>

</LinearLayout>

Im using RecyclerView v. 23.4.0.

Update

1. I have tried to call my RecyclerView item layout root requestLayout at the end of the adapter onBindViewHolder().

This does not any have affect, my views are not updated.

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

2. Maybe the problem is that the view is not yet completely drawn when I call requestLayout? So I tried to set GlobalLayoutListener and call requestLayout there. I think this helps little, but still if I have enough items, in my list not all views are updated. Owerall in my list I have around max 10 items.

ViewTreeObserver vto = viewHolder.mLayoutRoot.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        viewHolder.mLayoutRoot.requestLayout();
    }
});

3. I tried to use TableLayout with shrinkColumns property to approach similar layout, but the result is same. Name text view widht is not always correctly set. Also, it looks like requestLayout has no affect at all (or am I calling it in wrong place?)

4. (28/8/2016)

I stripped down my code to bare minimum to reproduce this.

I managed to fix this using setIsRecyclable(false), like dosssik suggests, but I think it is not very good solution in terms of performance?

Here is my full list item:

<?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:layout_width="wrap_content"
    android:layout_height="150dp"
    android:layout_marginLeft="16dp"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/name"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginRight="8dp"
        android:layout_weight="1"
        android:ellipsize="end"
        android:maxLines="1" />

    <TextView
        android:id="@+id/code"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/background_stop_code_small"
        android:ellipsize="end"
        android:paddingBottom="1dp"
        android:paddingLeft="7dp"
        android:paddingRight="7dp"
        android:paddingTop="1dp"
        android:singleLine="true"
        android:textSize="11sp"/>

</LinearLayout>

My adapter code:

I also tried to call invalidate(), but can not see any affect.

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    Item item = getItem(position);
    NormalViewHolder viewHolder = (NormalViewHolder) holder;

    viewHolder.mName.setText(item.getName());
    //viewHolder.mName.invalidate(); // No help
    viewHolder.mCode.setText(item.getCode());
    //viewHolder.mCode.invalidate(); // No help
}

Expected behaviour:

+----------------------------------------+
|[Name][Code]                            |
+----------------------------------------+
|[Name qwertyuiopasdfghjklzxcvb...][Code]|
+----------------------------------------+

This is how works right now if I scroll list up/down. So the layout is not updated and code is not alignet right to name. Also name is not taking always enough space.

+----------------------------------------+
|[Name][Code]                            |
+----------------------------------------+
|[Name qwer...]                [Code]    |
+----------------------------------------+
|[Name qwertyuiopa][Code]                |
+----------------------------------------+
|[Name qwe]        [Code]                |
+----------------------------------------+
like image 616
devha Avatar asked Aug 18 '16 20:08

devha


1 Answers

I share my solution which is not need to use

setIsRecyclable(false)

Use below custom TextView at your xml.

public class TextViewForRecyclerView extends android.support.v7.widget.AppCompatTextView {
    public TextViewForRecyclerView(Context context) {
        super(context);
    }

    public TextViewForRecyclerView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public TextViewForRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public void setText(CharSequence text, BufferType type) {
        super.setText(text, type);
        requestLayout();
    }
}
like image 55
하준영 Avatar answered Oct 20 '22 11:10

하준영