2
votes

tl;dr: How to achieve the layout shown in the screenshot below? Placing ListView to a ScrollView is apparently not recommended, but is there actually any other way to achieve it?

The whole question: I want to have multiple CardViews in my app, and one (or more) of them will have either RecyclerView or ListView in it (it doesn't really matter to me which one of those). The whole view is supposed to be scrollable - not only the ListViews in their parent CardViews. I basically need to achieve similar layout as the Play Store app has.

Play Store's My Apps screen

The first option I tried was this (the code is obviously simplified):

<LinearLayout android:orientation="vertical">
    <CardView>
        <!-- Some content of the first card. -->
    </CardView>
    <CardView>
        <ListView/>
    </CardView>
</LinearLayout>

The result was not what I wanted, the ListView was only scrollable in its parent CardView but the whole view wasn't scrollable like it is in the Play Store app. So now I wrapped it all in a ScrollView:

<ScrollView 
    android:fillViewport="true"
    android:isScrollContainer="true">
    <LinearLayout orientation="vertical">
        <CardView>
            <!-- Some content of the first card. -->
        </CardView>
        <CardView>
            <ListView/>
        </CardView>
    </LinearLayout>
</ScrollView>

And I programmatically set the height of the bottom card to fit the ListView's height (number of elements in the ListView * height of one list item element). Now the whole view is scrollable, and the bottom card's height is the same as the height of the ListView, so the ListView isn't scrollable inside the CardView which is exactly what I wanted.

Now the actual problem: I got it working as described above, but I know this particular issue (ListView in a ScrollView) has been asked about many times before and the answer has always been the same - don't put neither RecyclerView nor ListView in a ScrollView because it causes performance problems. Well, so what's the correct approach then? How did Google do it in the Play Store app? I tried decompiling the Play Store app with APKTool but there weren't any layout files (maybe I did something wrong). Is my approach correct? My ListView will only display a few items (I guess it will be at most 20 items) - will it cause some performance issues in this case?

I wouldn't ask about this if all the answers wouldn't always mention that we shouldn't put ListView in a ScrollView. Is there any other way how to achieve the layout described by the screenshot above?

2

2 Answers

2
votes

The first thing to address is why you're "not supposed to" use wrap_content on a ListView or a RecyclerView and put it in a scrollable container: it defeats the entire view-recycling purpose of these components.

What makes a ListView or RecyclerView better than a LinearLayout inside a ScrollView is that the system only needs to create enough views to display everying that fits inside the visible area. When you "scroll" the visible area, the views that disappear off one end can be re-used for the views that scroll into view from the other end. When you make your list/recycler wrap_content, this recycling is impossible, so you might as well just manually add your views to a LinearLayout instead.

That being said, RecyclerView does support using wrap_content... it just means you won't get view recycling. If this performance hit doesn't cause you problems, there's no objectively evil code here.

The only way to know for sure if the performance penalty is problematic or not is to just try it, test it, measure it, and decide for yourself. With 20 items, I suspect you have nothing to worry about.

The next thing to think about is the fact that Google has tons of resources and manpower and can afford to be extremely clever. Perhaps the Play Store app is as you say, with some sort of scrollable parent container that holds cards, each of which have some sort of adapter view within. But it's equally possible that they're doing something completely different, like using a single RecyclerView and "faking" the appearance of cards by using an ItemDecoration. Or perhaps they are using some sort of custom view subclass that the public doesn't have access to.

As for how you could recreate something similar, I suspect a hierarchy like this will work just fine:

<NestedScrollView>
  <LinearLayout>
     <CardView>
       <RecyclerView/>
     </CardView>
     <CardView>
       <RecyclerView/>
     </CardView>
     <CardView>
       <RecyclerView/>
     </CardView>
  </LinearLayout>
</NestedScrollView>
0
votes

I would recommend you to use Sectioned RecyclerView for this purpose. Every single item layout would have a cardView in it instead of creating a cardView as a parent.

Refer to this library: https://github.com/luizgrp/SectionedRecyclerViewAdapter