44

So I need a horizontal RecyclerView. However, the items in them have dynamic heights based on what's returned from the backend.

The RecyclerView and its items have the height of "wrap_content"

The problem is if the first visible items in the RecyclerView are small, then when the user scrolls to the larger items, they appear cut off.

Ideally, we want the RecyclerView to be large enough to hold the largest item in the group (but only the largest existing item... not the hypothetically largest item). The RecyclerView dynamically changing its height is also acceptable.

I wrote an example app to illustrate the problem. In this app, we have a horizontal list. The first 33 items should show 1 line of text, while the next should show 3 lines of text, and the last 34 should show 2 lines. However, they all show 1 line, because the height of the RecyclerView doesn't change.

I've tried calling requestLayout() on the RecyclerView (and on the TextView) from onBindViewHolder(), but it doesn't seem to do anything.

MainActivity:

public class MainActivity extends AppCompatActivity {

    private RecyclerView mRecyclerView;
    private RecyclerView.Adapter mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mAdapter = createAdapter();

        mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
        mRecyclerView.setAdapter(mAdapter);
    }

    private RecyclerView.Adapter<ViewHolder> createAdapter() {
        RecyclerView.Adapter adapter = new RecyclerView.Adapter<ViewHolder>() {
            @Override
            public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
                View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
                return new ViewHolder(v);
            }

            @Override
            public void onBindViewHolder(ViewHolder holder, int position) {
                if (position < 33) {
                    holder.mText.setText("1 line");
                } else if (position > 66) {
                    holder.mText.setText("2 lines\n2 lines");
                } else {
                    holder.mText.setText("3 lines\n3 lines\n3 lines");
                }
            }

            @Override
            public int getItemCount() {
                return 100;
            }
        };
        return adapter;
    }

    private static class ViewHolder extends RecyclerView.ViewHolder {
        TextView mText;
        public ViewHolder(View itemView) {
            super(itemView);
            mText = (TextView) itemView.findViewById(R.id.text);
        }
    }
}

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</RelativeLayout>

item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="#888888">
    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hi"
        android:textSize="30sp" />

</LinearLayout>
Kartik Agarwal
  • 1,129
  • 1
  • 8
  • 27
Gak2
  • 2,661
  • 1
  • 16
  • 28

7 Answers7

1

Change your item.xml layout content with the below code. It will solve your issue.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="160dp"
    android:layout_height="match_parent"
    android:background="#888888">
    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hi"
        android:textSize="30sp" />

</LinearLayout>
Yahya M
  • 392
  • 3
  • 13
0

Change your recyclerView height & width from wrap_content to match_parent or you can also give fixed height to your recyclerView like android:layout_height="150dp"

 <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#888888" />

</RelativeLayout>

or You can try

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="150dp"
        android:background="#888888" />

</RelativeLayout>
Mahendra Gohil
  • 380
  • 1
  • 3
  • 21
SAVALIYA REENA
  • 218
  • 2
  • 15
0

You can solve this issue using the FlexboxLayoutManager Google library by defining the FlexDirection to FlexDirection.ROW and FlexWrap to FlexWrap.NOWRAP and also in your BaseViewHolder constructor set for each item the FlexShrink to 0.0f to be able to scroll horizontally. More details of how to achieve this can be found here: Horizontal RecyclerView with dynamic item’s Height

MariosP
  • 8,300
  • 1
  • 9
  • 30
0

MainActivity:

public class MainActivity extends AppCompatActivity {

    private RecyclerView mRecyclerView;
    private RecyclerView.Adapter mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mAdapter = createAdapter();

        mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
        mRecyclerView.setAdapter(mAdapter);
    }

    private RecyclerView.Adapter<ViewHolder> createAdapter() {
        RecyclerView.Adapter adapter = new RecyclerView.Adapter<ViewHolder>() {
            @Override
            public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
                View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
                return new ViewHolder(v);
            }

            @Override
            public void onBindViewHolder(ViewHolder holder, int position) {
                if (position < 33) {
                    holder.mText.setText("1 line");
                } else if (position > 66) {
                    holder.mText.setText("2 lines\n2 lines");
                } else {
                    holder.mText.setText("3 lines\n3 lines\n3 lines");
                }
            }

            @Override
            public int getItemCount() {
                return 100;
            }
        };
        return adapter;
    }

    private static class ViewHolder extends RecyclerView.ViewHolder {
        TextView mText;
        public ViewHolder(View itemView) {
            super(itemView);
            mText = (TextView) itemView.findViewById(R.id.text);
        }
    }
}

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</RelativeLayout>

item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="#888888">
    <TextView
        android:id="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Hi"
        android:textSize="30sp" />

</LinearLayout>
Adin D
  • 61
  • 4
0

To make RecyclerView Horizontal you need to use android:layout_centerHorizontal="true". Also, everything more are the same as vertical.

<androidx.recyclerview.widget.RecyclerView
        android:id="@+id/RecyclerView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_below="@id/toolbar"/>
-1

Try to add your textView android:singleLine="false" it changes when there are multiple lines

phoenixstudio
  • 1,776
  • 1
  • 14
  • 19
GolnazTorabi
  • 50
  • 1
  • 3
-7

Just call itemAdapter.notifyDataSetChanged();