57

I want to set Max Height of RecylerView.I am able to set max height using below code.Below code makes height 60% of current screen.

     DisplayMetrics displaymetrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
    int a = (displaymetrics.heightPixels * 60) / 100;
    recyclerview1.getLayoutParams().height = a;

But now problem is that, if it have no item then also its height is 60%. So I want to set its height 0 when no item in it.

I want to achieve something like this.

    if(recyclerview's height > maxHeight)
then set recyclerview's height to maxHeight
    else dont change the height of recyclerview.

How can i set it? Please help me, I am stuck with it

Maulik Dhameliya
  • 1,470
  • 1
  • 17
  • 21

12 Answers12

54

ConstraintLayout offers maximum height for its children.

<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ListView
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:scrollbars="vertical"
        app:layout_constrainedHeight="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHeight_max="300dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>
Ismail Iqbal
  • 2,774
  • 1
  • 25
  • 46
user1506104
  • 6,554
  • 4
  • 71
  • 89
  • 8
    Looks like the best solution. Sadly, but it doesn't work. – anro Jun 11 '19 at 11:13
  • 1
    Make sure to update the constraint layout dependency or else there is a bug in older versions where the recycler view is hidden when the recycler view becomes scrollable – Ismail Iqbal Sep 08 '20 at 14:09
  • This solution is perfect! and fixed my ADA as well. thank-you so much. app:layout_constraintHeight_max="300dp" -> very valuable! – SlowLearnah Aug 10 '22 at 00:44
52

Here is something, you need. Subclass the RecyclerView and override onMeasure as following:

@Override
protected void onMeasure(int widthSpec, int heightSpec) {
    heightSpec = MeasureSpec.makeMeasureSpec(Utils.dpsToPixels(240), MeasureSpec.AT_MOST);
    super.onMeasure(widthSpec, heightSpec);
}

Make sure, you give proper number of pixels as the first argument in makeMeasureSpec(). I personally needed RecyclerView, that is 240dps at most.

Fattum
  • 996
  • 1
  • 9
  • 23
  • 3
    How did u subclass the RecyclerView, please? – Dusan Jan 08 '18 at 08:32
  • 6
    @Dusan created a new class, that extended RecyclerView. – Fattum Jan 09 '18 at 18:36
  • 5
    This solution works when you add elements in Array but doesn't work when you remove the elements from the array. That means we can not decrease the height of the RecyclerView once we increased the height. – Viks Mar 12 '18 at 07:13
  • 3
    This is literally the only way to have a recycler view with a max height. Bad Google. – Daniel Wilson May 25 '18 at 10:41
34

I think this will work at least it worked for me

<androidx.constraintlayout.widget.ConstraintLayout
                android:id="@+id/Id_const_layout"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
               >
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/Id_my_recycler"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/margin_top_space"
            android:scrollbars="vertical"
            app:layout_constrainedHeight="true"
            app:layout_constraintBottom_toBottomOf="@+id/Id_const_layout"
            app:layout_constraintEnd_toEndOf="@+id/Id_const_layout"
            app:layout_constraintHeight_max="150dp"
            app:layout_constraintHeight_min="30dp"
            app:layout_constraintStart_toStartOf="@+id/Id_const_layout"
            app:layout_constraintTop_toTopOf="@+id/Id_const_layout"
            >
        </androidx.recyclerview.widget.RecyclerView>
            </androidx.constraintlayout.widget.ConstraintLayout>

You can change the constraintHeight_max and constraintHeight_min according to your needs.

Dhyan V
  • 621
  • 1
  • 8
  • 18
25

We can optimize @Fattum 's method a little bit. We can use app:maxHeight to set the maxHeight. One can use dp or px as you like.

public class MaxHeightRecyclerView extends RecyclerView {
    private int mMaxHeight;

    public MaxHeightRecyclerView(Context context) {
        super(context);
    }

    public MaxHeightRecyclerView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initialize(context, attrs);
    }

    public MaxHeightRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initialize(context, attrs);
    }

    private void initialize(Context context, AttributeSet attrs) {
        TypedArray arr = context.obtainStyledAttributes(attrs, R.styleable.MaxHeightScrollView);
        mMaxHeight = arr.getLayoutDimension(R.styleable.MaxHeightScrollView_maxHeight, mMaxHeight);
        arr.recycle();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (mMaxHeight > 0) {
            heightMeasureSpec = MeasureSpec.makeMeasureSpec(mMaxHeight, MeasureSpec.AT_MOST);
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
}

values/attrs.xml

<declare-styleable name="MaxHeightScrollView">
    <attr name="maxHeight" format="dimension" />
</declare-styleable>
M.J.M
  • 303
  • 1
  • 8
Francis Bacon
  • 4,080
  • 1
  • 37
  • 48
  • 2
    This solution works when you add elements in Array but doesn't work when you remove the elements from the array. That means we can not decrease the height of the RecyclerView once we increased the height. – Viks Mar 12 '18 at 07:09
16

After trying way too many complicated suggestions, I finally figured this out through trial and error.

First, wrap the RecyclerView in some sort of layout. In my case, I used a constraint layout, and I even had other elements in that layout above and below the RecyclerView. Set the height of the layout to auto adjust by setting it to 0dp, then set the default layout height constraint as wrap and define a layout max height constraint.

Then, on your RecyclerView, set the height to wrap_content and layout_constrainedHeight to true.

Here is what it should look like:

<android.support.constraint.ConstraintLayout
    android:layout_width="600px"
    android:layout_height="0dp"
    app:layout_constraintHeight_default="wrap"
    app:layout_constraintHeight_max="450px">

    <android.support.v7.widget.RecyclerView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constrainedHeight="true"
        app:layout_constraintTop_ToTopOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"/>

</android.support.constraint.ConstraintLayout>

Hope this helps!

Mitchell
  • 177
  • 1
  • 3
3

ill add my 2 cents i needed a recycler view with a max height and min height and wrap content between the 2

        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:id="@+id/group_card_recycler_view_holder"
            app:layout_constraintHeight_default="wrap"
            app:layout_constraintHeight_max="@dimen/group_recycler_view_height"
            app:layout_constraintHeight_min="@dimen/card_sentence_height"
            android:layout_marginTop="@dimen/activity_horizontal_margin_8dp"
            app:layout_constraintTop_toBottomOf="@id/group_name_container"
            app:layout_constraintBottom_toTopOf="@id/myButtonLayout">


            <androidx.recyclerview.widget.RecyclerView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                app:layout_constrainedHeight="true"
                android:id="@+id/group_card_recycler_view"/>


        </androidx.constraintlayout.widget.ConstraintLayout>
martinseal1987
  • 1,862
  • 8
  • 44
  • 77
2

write this statements inside if else and let me know ,

ViewGroup.LayoutParams params=recyclerview.getLayoutParams();
params.height=100;
recyclerview.setLayoutParams(params);
Radhey
  • 2,139
  • 2
  • 24
  • 42
  • > set its height 0 when no item in it.how could you determine this ?@Maulik009 , at that place . yes @Piyush ,bhai :) – Radhey Mar 09 '17 at 11:50
1

You can use WRAP_CONTENT in your RecyclerView. It will auto measure your recyclerview according to its content.

You can also calculate current height and set max height. So Recyclerview will use wrap_content attribute value until max height.

public static void getTotalHeightofRecyclerView(RecyclerView recyclerView) {

        RecyclerView.Adapter mAdapter = recyclerView.getAdapter();

        int totalHeight = 0;

        for (int i = 0; i < mAdapter.getItemCount(); i++) {
            View mView = recyclerView.findViewHolderForAdapterPosition(i).itemView

            mView.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
                    View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));

            totalHeight += mView.getMeasuredHeight();
        }

        if (totalHeight > 100) {
            ViewGroup.LayoutParams params = recyclerView.getLayoutParams();
            params.height = 100;
            recyclerView.setLayoutParams(params);
        }
    }
mertsimsek
  • 266
  • 2
  • 10
  • 1
    I have kept wrap_content in layout. But i want to set its Max Height so that it will scroll in current screen only. Because I have buttons below it that i want to show always. – Maulik Dhameliya Mar 09 '17 at 12:11
  • Caused by: java.lang.NullPointerException: Attempt to read from field 'android.view.View android.support.v7.widget.RecyclerView$ViewHolder.itemView' on a null object reference err on line View mView = recyclerView.findViewHolderForAdapterPosition(i).itemView – Maulik Dhameliya Mar 09 '17 at 12:32
  • can you share code? Looks like you are calling notifyDataSetChange() just before findViewHolderForAdapterPosition. – mertsimsek Mar 09 '17 at 12:37
  • No i am not calling notifyDataSetChange. – Maulik Dhameliya Mar 09 '17 at 12:50
  • recyclerview1.setAdapter(sectionAdapter1); recyclerview1.setLayoutManager(new LinearLayoutManager(this)); RecyclerView.Adapter mAdapter = recyclerview1.getAdapter(); getTotalHeightofRecyclerView(recyclerview1); – Maulik Dhameliya Mar 09 '17 at 12:50
1

If you have a RecyclerView designed to hold items of equal physical size and you want a no-brainer way to limit its height without extending RecyclerView, try this:

int maxRecyclerViewHeightPixels = (int) TypedValue.applyDimension(
    TypedValue.COMPLEX_UNIT_DIP,
    MAX_RECYCLERVIEW_HEIGHT_DP,
    getResources().getDisplayMetrics()
);

MyRecyclerViewAdapter myRecyclerViewAdapter = new MyRecyclerViewAdapter(getContext(), myElementList);
myRecyclerView.setAdapter(myRecyclerViewAdapter);

ViewGroup.LayoutParams params = myRecyclerView.getLayoutParams();

if (myElementList.size() <= MAX_NUMBER_OF_ELEMENTS_TO_DISPLAY_AT_ONE_TIME) {
    myRecyclerView.setLayoutParams(new LinearLayout.LayoutParams(
         LinearLayout.LayoutParams.MATCH_PARENT,
         LinearLayout.LayoutParams.WRAP_CONTENT));
    //LinearLayout must be replaced by whatever layout type encloses your RecyclerView
}
else {
    params.height = maxRecyclerViewHeightPixels;
    myRecyclerView.setLayoutParams(params);
}

This works both for Linear and Grid RecyclerViews, you just need to play with the numbers a bit to suit your taste. Don't forget to set the height to WRAP_CONTENT after you populate the RecyclerView.

You may also have to set the height again every time the size of myElementList changes, but that's not a big issue.

BarLr
  • 139
  • 1
  • 5
1

The simplest way is to use ConstraintLayout and setting height constraint on Recycleview.

<android.support.constraint.ConstraintLayout
    android:id="@+id/CL_OUTER_RV_Choose_Categories "
    android:layout_width="match_parent"
    android:layout_height="200dp">

   <android.support.v7.widget.RecyclerView
        android:id="@+id/RV_Choose_Categories"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="vertical"
        app:layout_constrainedHeight="true" >
    </android.support.v7.widget.RecyclerView>

</android.support.constraint.ConstraintLayout>

Please note that before Lollipop, the recycleview will not scroll. As a solution, add the below code in the activity's oncreate.

if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
        ConstraintLayout CL_OUTER_RV_Choose_Categories = findViewById(R.id.CL_OUTER_RV_Choose_Categories);
        LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) CL_OUTER_RV_Choose_Categories.getLayoutParams();
        lp.height = LinearLayout.LayoutParams.WRAP_CONTENT;
    }

This will ensure that height is fixed only on supported devices, and the complete recycle view is shown on older devices.

Do let me know if there is any better way.

Hemant Aggarwal
  • 849
  • 1
  • 7
  • 13
0

I just had this same problem, and wanted to share a new, up-to-date answer. This one works on at least Android 9 and Android Studio v. 4.0.

Wrap the RecyclerView in a ConstraintLayout, as some of the answers here have suggested. But it does not appear you can set the maximum height of that layout in XML. Instead, you must set it in code, as follows: Give the ConstraintLayout an ID, and then, in your onCreate or onViewCreated method for the activity or fragment, respectively, in question - for example, to set a max height of 200 dp:

findViewById<ConstraintLayout>(R.id.[YOUR ID]).maxHeight = 200 // activity
view.findViewById<ConstraintLayout>(R.id.[YOUR ID]).maxHeight = 200 // fragment

Annoyingly, ConstraintLayout does expose an XML attribute android:minHeight but no android:maxHeight.

Even more annoyingly, RecyclerView itself apparently comes with an XML attribute named android:maxHeight, but that attribute does not work.

The_Sympathizer
  • 1,191
  • 9
  • 17
-6

You can just set a specific height to any value in the xml code and set the visibility to gone. Then you set the visibility to Visible in Java, when you want to inflate it. Here is an example;

.xml

android:visibility="gone"

.java

recyclerView.setVisibility(View.VISIBLE);
Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
Seyi
  • 35
  • 1
  • 2