14

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.

Tariq
  • 593
  • 2
  • 7
  • 21
  • 5
    If you're going to downvote my question, please tell me why... – Tariq Aug 13 '15 at 19:33
  • possible duplicate of [How to show an empty view with a RecyclerView?](http://stackoverflow.com/questions/28217436/how-to-show-an-empty-view-with-a-recyclerview) – Jared Burrows Aug 13 '15 at 20:14
  • That's not my question at all. His question is really not even a layout question. And believe me I've looked all over and tried numerous solutions to similar problems. If you find one that works that I'll be glad. – Tariq Aug 13 '15 at 20:18
  • is your recycler view always shorter than one height of a screen and you actually never scroll on it? – dkarmazi Aug 13 '15 at 21:23
  • Hm no my RecylerView is always at least one height of a screen. I can tell by the overscroll effect – Tariq Aug 13 '15 at 23:11
  • http://stackoverflow.com/questions/27475178/how-do-i-make-wrap-content-work-on-a-recyclerview – tachyonflux Aug 18 '15 at 00:34
  • What's preventing you from specifying the background color for FrameLayout and getting rid of the the empty View once and for all? – JanithaR Aug 18 '15 at 06:25

5 Answers5

6

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.

Marcin Orlowski
  • 72,056
  • 11
  • 123
  • 141
Vishal Makasana
  • 960
  • 2
  • 7
  • 15
  • This works thanks. However I used the simpler extended version of LinearLayoutManger here: http://stackoverflow.com/questions/26649406/nested-recycler-view-height-doesnt-wrap-its-content/28510031#28510031 that also takes into account swiping, drag sorting, and item decorations. – Tariq Aug 18 '15 at 18:00
1

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>
Prasad
  • 3,462
  • 1
  • 23
  • 28
0

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.

Andrea Thacker
  • 3,440
  • 1
  • 25
  • 37
  • Again doesn't work because the RecyclerView takes up the whole space. I tried setting the height of the View to 0 and weight to 1 but that didn't work. Tried the same with the RecyclerView while keeping View at match_parent height but that didn't work either. My RecyclerView contents are set dynamically. I don't know what the issue but thanks for the try. – Tariq Aug 13 '15 at 22:43
  • So do you have items in the RecyclerView that take up the whole screen? If you have more than enough items in your collection to fill the screen I don't see how this would be possible. – Andrea Thacker Aug 13 '15 at 22:45
  • No for now I'm just testing with a single item that takes up about a tenth of the screen. But when I try to scroll I tell from the overscroll effect that the RecyclerView is taking up the whole screen. – Tariq Aug 13 '15 at 22:49
  • This won't work because RecyclerView does not update it's height when new elements are drawn. But there is a work around, all you need is to leave RecyclerView for last on the file, check my answer. – Dpedrinha Nov 21 '15 at 20:41
0

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.

k1slay
  • 1,068
  • 1
  • 10
  • 18
0

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

}

Reaj
  • 11
  • 2