19

I have a vertical recyclerview (with a GridLayoutManager) inside another recyclerview (with LinearLayoutManager). The problem I am facing right now is that, the inner recyclerview (with GridLayoutManager) binds all of it's items at the same time, even the views that are not on the screen at the moment (onBindViewHolder() gets called for all of its items).

To give you more information, in my layout file, I put height of my recycler view as wrap_content.

I think the problem is, since there are 2 nested vertically recyclerviews, when the parent RV wants to measure its children and the children is another RV, in onMeasure() it computes the size needed for the entire RV, not just the portion that it wants to bind on the screen.

Any idea how to solve this?

Here is the layout file for my outer recyclerview:

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

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

</FrameLayout>

And here is the code for my inner recyclerview:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/gutter"
android:paddingBottom="@dimen/gutter">

<TextView
    android:id="@+id/title_text"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginBottom="@dimen/gutter"
    android:textSize="30sp"
    android:textColor="@android:color/white"
    android:fontFamily="sans-serif-thin"/>

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

</LinearLayout>

P.S.: I'm using this adapter delegate for my outer recyclerview: https://github.com/sockeqwe/AdapterDelegates

Gabriel
  • 578
  • 3
  • 8
  • 22
  • You're right on the problem- a recycler view has infinite length, so the child RV will think it fits every view just find. I'm not going to give an answer because I'm not 100% sure, but I think you're going to need to make a custom layout manager. – Gabe Sechan Jul 25 '16 at 19:18

5 Answers5

6

I think nested recyclerviews are a very bad idea. When i try to scroll, which recyclerview has to respond the the scolling, the parrent or child.

That is why I think you are looking for the ExpandableListView? That's limited to only two levels of listings, but that sounds like it would work for your needs). It also solves the soling issue.

It would look something like this:

enter image description here

EDIT: even nested ExpandableListViews are possible:

enter image description here

EDIT: check this lib for horizontal scroling

Robin Dijkhof
  • 18,665
  • 11
  • 65
  • 116
  • If you have multiple horizontal list how you handle this? – Amir Aug 01 '16 at 13:44
  • actually in my case it's different, I can't put any design screenshot here, but basically bunch of components in the outer RV, in which one of the components might be a RV with grid layout. So I don't think it's necessarily a bad idea, Depends on what you wanna do. Your solution doesn't work for me because of the design I have. – Gabriel Aug 02 '16 at 19:19
  • Can you add a small scetch? Someting in paint or so? – Robin Dijkhof Aug 02 '16 at 19:27
4

This is a known bug.
You should not put a RecyclerView inside another RecyclerView because RecyclerView gives its children infinite space.
Hence the inner RecyclerView keeps measuring till the dataset is exhausted.
Try setting setAutoMeasureEnabled(false) to false on layout manager or you can solve this problem by using a wrapper adapter instead of inner recycler view.

abhishesh
  • 3,246
  • 18
  • 20
0

The first thing you need to know is that, when you nest scrolling layouts, the inner ones will get infinity allowed height, effectively making them wrap_content. There is in fact a relatively easy way to fix this problem. Say I had two nested RecyclerViews such as these, in this case vertically oriented.

<RecyclerView 
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    android:orientation="vertical>
    <View .../>
    <!-- other stuff -->
    <RecyclerView 
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:orientation="vertical"/>
</RecyclerView>

The inner recyclerView here will bind all of it's children immediately every time because, from it's position, your screen will have infinite height.

The solution is to set the height of your inner recyclerview to some static value, not wrap_content or match parent, as either of those will simply fill up the outer recyclerview with one view that will all be bound at once due to it's large height. If you make the height of the inner recyclerview the same as the display's height, you should see your problem go away.

Here is an implementation that will not bind all children at once:

<RecyclerView 
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    android:orientation="vertical>
    <View .../>
    <!-- other stuff -->
    <RecyclerView 
         android:layout_width="match_parent"
         android:layout_height="@dimen/screen_height"
         android:orientation="vertical"/>
</RecyclerView>

Note the layout_height of the inner RecyclerView is now a fixed value pulled from the dimensions file. You yourself will have to come up with a reasonable value to put there.

Side Note: In order to make all of this work and for scrolling to work properly, you may have to play around with the parameter: NestedScrollingEnabled in your RecyclerViews - there are several known bugs relating to this that you may need to work around.

i.e.: innerRecyclerView.setHasFixedSize(true); and innerRecyclerView.setNestedScrollingEnabled(false).

John Gallagher
  • 525
  • 4
  • 15
  • 1
    I tried that before, the problem with this solution is that the scrolling won't work anymore. I even set nested scrolling to true, yet i had no chance. – Gabriel Jul 26 '16 at 00:17
  • You may need to set nested scrolling to false for the inner RecyclerView. Try `innerRecyclerView.setHasFixedSize(true);` and `innerRecyclerView.setNestedScrollingEnabled(false)`. – John Gallagher Jul 26 '16 at 13:46
  • If if do `innerRecyclerView.setNestedScrollingEnabled(false);` how am i supposed to scroll through all of my items in the RV? In that case it just shows a small set of my items in the RV. – Gabriel Jul 26 '16 at 16:29
  • I'm guessing you've tried all permutations of setHasFixedSize(boolean) and setNestedScrollingEnabled(boolean). Have you tried giving your inner recyclerview a max height? If not I would try doing only that to fix your initial problem and then if that doesn't work, could you provide some code in your question to help us figure this out? – John Gallagher Jul 26 '16 at 17:50
  • I'd love to see your the xml for your recyclerview as well as wherever you are binding the inner recyclerviews to the outer one. I'm going to implement this myself sometime today and I'll try to get back to you with that. – John Gallagher Jul 30 '16 at 13:13
  • something else you may want to think about is whether the outer recyclerview is necessary, in other words, are you only putting a few things in it? if that is the case, you may want to try a NestedScrollView with the recyclerView given a fixed height inside it. that would simplify things considerably and make fixing this problem easier. (in other words, you would no longer have to be binding one recyclerview to another). – John Gallagher Jul 30 '16 at 13:15
  • My outer RV is holding a bunch of components, in which one of the components is a RV with grid layout. – Gabriel Aug 02 '16 at 19:20
0

so what happens here when you place a scrollview(no fixed size because of wrap content) inside another scrollview(again no fixed size because of wrap content),both nested scroll view fails to render.

So there is two solutions--

1- Either you will have to think of alternative solution for nested scrollviews 2- You can give outside recyclerview cell fixed height so that inside recycler view can get some fixed layout to render itself.

  • #1) There is no alternative, that's based on the design #2) it's not gonna work cause if i give it a fixed height, it wont scroll – Gabriel Jul 29 '16 at 22:45
-3

I could solve my issue by using only one Recyclerview, where it has a grid layout, and based on the component items i'm adding into it, i change the spancount for that. Basically instead of adding the inner recyclerview, i add the items that were supposed to go to the inner recyclerview, to the outer recyclerview.

Gabriel
  • 578
  • 3
  • 8
  • 22