Making Recyclerview Fixed Height and Scrollable

So what my problem was that for some reason, Recyclerview didnt wrap_contents. I did some research (thanks stackoverflow) and found out a lot of people were having this issue and they posted solutions for this issue.

Basically, I had to use a customized linearlayoutmanger to fix the issue.

I will post the solution they posted and links to their questions. thanks for whoever tried to help, I appreciate it.

This is the extra file I needed. And then I had to set my recyclerview to use this layout instead of the default one.

public class MyLinearLayoutManager extends LinearLayoutManager {

public MyLinearLayoutManager(Context context, int orientation, boolean reverseLayout)    {
    super(context, orientation, reverseLayout);
}

private int[] mMeasuredDimension = new int[2];

@Override
public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state,
                      int widthSpec, int heightSpec) {
    final int widthMode = View.MeasureSpec.getMode(widthSpec);
    final int heightMode = View.MeasureSpec.getMode(heightSpec);
    final int widthSize = View.MeasureSpec.getSize(widthSpec);
    final int heightSize = View.MeasureSpec.getSize(heightSpec);
    int width = 0;
    int height = 0;
    for (int i = 0; i < getItemCount(); i++) {
        measureScrapChild(recycler, i,
                View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
                View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
                mMeasuredDimension);

        if (getOrientation() == HORIZONTAL) {
            width = width + mMeasuredDimension[0];
            if (i == 0) {
                height = mMeasuredDimension[1];
            }
        } else {
            height = height + mMeasuredDimension[1];
            if (i == 0) {
                width = mMeasuredDimension[0];
            }
        }
    }
    switch (widthMode) {
        case View.MeasureSpec.EXACTLY:
            width = widthSize;
        case View.MeasureSpec.AT_MOST:
        case View.MeasureSpec.UNSPECIFIED:
    }

    switch (heightMode) {
        case View.MeasureSpec.EXACTLY:
            height = heightSize;
        case View.MeasureSpec.AT_MOST:
        case View.MeasureSpec.UNSPECIFIED:
    }

    setMeasuredDimension(width, height);
}

private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
                               int heightSpec, int[] measuredDimension) {
    View view = recycler.getViewForPosition(position);
    if (view != null) {
        RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();
        int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,
                getPaddingLeft() + getPaddingRight(), p.width);
        int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,
                getPaddingTop() + getPaddingBottom(), p.height);
        view.measure(childWidthSpec, childHeightSpec);
        measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin;
        measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin;
        recycler.recycleView(view);
    }
}
}

After that. Change this:

 mProductsRecyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));

To this:

mRecyclerView.setLayoutManager(new MyLinearLayoutManager(getApplicationContext(),1,false));

Three new paramets(Context, int Orientation, boolean reverse); basically, i put 1 for orientation so it shows vertiacally, and false for revers so it shows up how it is ordered in my List.

Links to other people's question with same problem as me. Nested Recycler view height doesn't wrap its content

Nested Recycler view height doesn't wrap its content

Thanks once again guys. Hope this helps someone else


In my situation I had a DialogFragment, in which there are 2 recyclers and 2 horizontal linear layouts with 2 buttons.

Dialog from top to bottom looks like this:

  • RecyclerView A
  • Horizontal linear layout X with 2 buttons
  • RecyclerView B
  • Horizontal linear layout Y with 2 buttons

On top of that both recyclers size is dynamic. Recycler A size can change based on user swipes in both recyclers. Recycler B size can change based on its item click listener.

What I wanted to achieve was to cut the Dialog from top to bottom and have each of those four views its constant part of the Dialog height.

What worked was to divide it first to 2 separate relative layouts, say lTOP and lBottom. Set lTOP alignParentTop, lBottom alignParentBottom and layout_below lTOP. Both of them width match_parent, height wrap_content.

Then in each of them create 1 relative (say lINTop) and 1 linear (say lINBottom) layouts. lINTop has recycler, lINBottom has 2 buttons. Set both lINTop lINBottom width match_parent, height wrap_content. Set lINTop alignParentTop, lINBottom alignParentBottom and below lINTop. Set lINTop orientation vertical, lINBottom orientation horizontal.

Set recyclers width match_parent, height wrap_content.

Then i putted this all inside single relative layout with width/height wrap_content and orientation vertical. Then this inside scrollview with width/height match_parent and orientation vertical.

Then needed a little code magic for setting up recycler in onCreateView:

For Recycler A:

private void setupRecyclerA() {
    // use a linear layout manager
    RecyclerView.LayoutManager layManUS = new LinearLayoutManager(setupActivity().get());
    recyclerA.setLayoutManager(layManUS);
    recyclerA.addItemDecoration(new DividerItemDecoration(
            setupActivity().get(), LinearLayoutManager.VERTICAL));
    recyclerA.setNestedScrollingEnabled(true);
    // use this setting to improve performance if you know that changes
    // in content do not change the layout size of the RecyclerView
    recyclerA.setHasFixedSize(true);
}

For Recycler B:

private void setupRecyclerB() {
    // use a linear layout manager
    RecyclerView.LayoutManager layManUS = new LinearLayoutManager(setupActivity().get());
    recyclerB.setLayoutManager(layManUS);
    recyclerB.addItemDecoration(new DividerItemDecoration(
            setupActivity().get(), LinearLayoutManager.VERTICAL));
    recyclerB.setNestedScrollingEnabled(true);
    // set fixed height
    DisplayMetrics displaymetrics = new DisplayMetrics();
    setupActivity().get().getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
    // set height to 30 percent of dialog
    int a =  (displaymetrics.heightPixels*30)/100;
    recyclerB.getLayoutParams().height =a;
    // use this setting to improve performance if you know that changes
    // in content do not change the layout size of the RecyclerView
    recyclerB.setHasFixedSize(true);
}

I didnt invented it, I just combined solutions from many different Stack Overflow questions which I dont even remember now, sorry and thanks to the Creators.


Add this code in your activity, will set the height of your recycler view to the 90% of user's screen window.

DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);

int a =  (displaymetrics.heightPixels*90)/100;

recylcerView.getLayoutParams().height =a;

and your comment layout below the your recyclerView

like this

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <LinearLayout
        android:layout_alignParentTop="true"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" 
        android:id="@+id/mudit"
        >

        <android.support.v7.widget.RecyclerView
            android:id="@+id/my_recycler_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:elevation="5dp"
            android:scrollbars="vertical" />
    </LinearLayout>

    <RelativeLayout
        android:layout_below="@+id/mudit"
        android:id="@+id/rl_commentWrap"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true" >

        <EditText
            android:id="@+id/editText1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentLeft="true"
            android:ems="10" />

        <Button
            android:id="@+id/plusButton"
            style="android:buttonStyleSmall"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:text="Send"
            android:textColor="#FFFFFF"
            android:translationZ="5dp" />
    </RelativeLayout>

</RelativeLayout>