Tariq
Tariq

Reputation: 593

Make empty view take up remaining space after RecyclerView?

I'm trying to make an empty view that is colored take up the remaining space after a RecyclerView. I've looked at different StackOverflow solutions but nothing works. Essentially I want something like this :

________________________
|                       |
|                       |
|                       |
|    Recycler view      |
|                       |
|  -------------------  |
|    colored empty view |
|                       |
|                       |
|                       |
|                       |
|                       |
_________________________

It should shrink as the RecyclerView grows. 

________________________
|                       |
|                       |
|                       |
|    Recycler view      |
|                       |
|                       |
|                       |
|                       |
|                       |
|  -------------------  |
|    colored empty view |
|                       |
|                       |
_________________________

However if the RecyclerView exceeds one screen's worth, there should be no empty view. Here's what I have so far:

 <?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:fab="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/bla_bla_layout">


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

    <View
        android:background="@color/grayBackground"
        android:layout_gravity="bottom"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <com.melnykov.fab.FloatingActionButton
        android:id="@+id/fab"
        android:contentDescription="@string/add_bla"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|right"
        android:layout_margin="16dp"
        android:src="@drawable/add_bla_icon"
        fab:fab_colorNormal="@color/primary"
        fab:fab_colorPressed="@color/primary_pressed"
        fab:fab_colorRipple="@color/ripple" />

</FrameLayout>

EDIT This is not a duplicate of the mentioned question and you could see this if you read both questions. The solution to my question should be purely xml, layout based. By "empty view" I mean just some colored rectangle BELOW the existing RecyclerView, not a textview that actually says "Empty view" when there's no data in the RecylerView.

Upvotes: 14

Views: 12078

Answers (5)

Vishal Makasana
Vishal Makasana

Reputation: 960

Recycler view calculate its height at runtime and we uses LinearLayoutManager to specify its height and width.

But problem is that, right now LinearLayoutManager does not support wrap_content it uses always match_parent for it's height.

So you have to use this LinearLayoutManager not android.support.v7.widget.LinearLayoutManager.

copy above java class in your package and use it like below,

LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this,
            LinearLayoutManager.VERTICAL, false);
recyclerView.setLayoutManager(linearLayoutManager);
// if it has fixed size
recyclerView.setHasFixedSize(true);

I tested it and its working as you need.

Upvotes: 6

Reaj
Reaj

Reputation: 11

Use a custom LinearLayoutManager hopefully its solve your problem.

use this code in your activity

 RecycleView rv= (RecyclerView) rootView.findViewById(R.id.recycler_view);
   CustomLinearLayoutManager lm= new CustomLinearLayoutManager(mActivity);
    lm.setOrientation(LinearLayoutManager.VERTICAL);
    lm.setHasFixedSize(true);
    rv.setLayoutManager(lm);

Here is my CustomLinearLayoutManager

public class CustomLinearLayoutManager extends LinearLayoutManager {

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

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);

    measureScrapChild(recycler, 0,
            View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
            View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
            mMeasuredDimension);

    int width = mMeasuredDimension[0];
    int height = mMeasuredDimension[1];

    switch (widthMode) {
        case View.MeasureSpec.EXACTLY:
        case View.MeasureSpec.AT_MOST:
            width = widthSize;
            break;
        case View.MeasureSpec.UNSPECIFIED:
    }

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

    setMeasuredDimension(width, height);
}

private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
                               int heightSpec, int[] measuredDimension) {
    try {
        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();
            measuredDimension[1] = view.getMeasuredHeight();
            recycler.recycleView(view);
        }
    }catch(Exception e){
        e.printStackTrace();
    }
}

}

Upvotes: 0

k1slay
k1slay

Reputation: 1088

If you just want a different color in the remaining space, set the FrameLayout's background to the desired color and set the RecyclerView item's layout background to white.

This will result in the remaining space in a separate color and the length of the populated items in recyclerView will be white just as you need.

If you want some other view in the remaining space like a textView or an ImageView I guess you will have to extend RecyclerView class and override the method which calculates it's height.

Upvotes: 0

Andrea Thacker
Andrea Thacker

Reputation: 3470

It looks like you could accomplish with a RelativeLayout using some align commands.

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

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

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

        <View
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@+id/recycler_view"
            android:layout_alignParentBottom="true"
            android:background="@color/blue"/>

    </RelativeLayout>

</FrameLayout>

I included the FrameLayout because you mentioned in another comment that you needed it to use with a FAB.

If you load this into AndroidStudio and start setting sample widths (50dp, 150dp, 300dp...) for the height of the RecyclerView you will see the View below it start to adjust its height as well.

Upvotes: 0

Prasad
Prasad

Reputation: 3562

Try this

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/bla_bla_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <android.support.v7.widget.RecyclerView
        android:id="@+id/bla_bla_recyclerview"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:entries="@array/array_sample" />

    <View
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:background="@color/grayBackground" />

</LinearLayout>

Upvotes: 1

Related Questions