Recyclerview binds all views at the same time
Asked Answered
C

5

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

Chare answered 21/7, 2016 at 18:55 Comment(1)
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.Piave
P
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

Paratuberculosis answered 31/7, 2016 at 21:19 Comment(3)
If you have multiple horizontal list how you handle this?Morelock
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.Chare
Can you add a small scetch? Someting in paint or so?Paratuberculosis
L
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.

Lamelli answered 26/7, 2016 at 14:11 Comment(9)
If it's a known bug, can you please point me to the reported bug in google forum?Chare
Also, I used setAutoMeasureEnable(false);, the thing is, from then on, i have to measure it myself, which i tried to do that by creating my own LayoutManager, but i don't know how exactly to create my own layout manager properly.Chare
I'd suggest you to use wrapper adapter insteadLamelli
Can you elaborate more? Do you mean WrapperListAdapter?Chare
Can you post some code here, or on github. I ll explain using your codeLamelli
adapter part of both recycler viewLamelli
by wrapper adapter I mean, whatever binding part you are doing in inner recycler view adapter, do it in your outer recycler adapter Consider child of your inner recycler view as direct child of outer recycler view. This way you will not need inner recycler view.Lamelli
I updated my post with some code and more information.Chare
you saved my day!!Gorga
F
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).

Furey answered 25/7, 2016 at 19:26 Comment(7)
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.Chare
You may need to set nested scrolling to false for the inner RecyclerView. Try innerRecyclerView.setHasFixedSize(true); and innerRecyclerView.setNestedScrollingEnabled(false).Furey
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.Chare
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?Furey
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.Furey
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).Furey
My outer RV is holding a bunch of components, in which one of the components is a RV with grid layout.Chare
C
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.

Cocoa answered 29/7, 2016 at 14:20 Comment(1)
#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 scrollChare
C
-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.

Chare answered 2/8, 2016 at 23:36 Comment(1)
Thats not a real solutionAcrobatic

© 2022 - 2024 — McMap. All rights reserved.