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.
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?
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>
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
Related
I've the following use case -
<ScrollView> // parent
<ContentView/> // content
</ScrollView>
I do not have any access to the parent ScrollView because the library only allows setting the content view. And it doesn't provide any API or reference to modify the attributes of the parent ScrollView. And the content of ContentView is arbitrary in a way that it can take recycler-view, list-view and any other views with scrolling effects.
Because I do not have access to the parent ScrollView, I can't change its property / attributes anyhow. This causes the issue will ill-behaved scrolling. This specially shows the problem when
<ScrollView>
<ContentView>
<LinearLayout orientation=horizonal>
<RecyclerView/>
<RecyclerView/>
</LinearLayout>
<ContentView>
<ScrollView
And this causes two recycler-views to scroll together, while I want individual recycler-view scroll independently.
I was thinking of a solution that I can build a container-view and the children of container-view are agnostic of its ScrollView parent. So that my recycler-views have no knowledge of its parent ScrollView.
Is there any way to implement such solution? Have you ever encountered such an issue and how did you fix it?
I want to use multiple ListView/GridView within same User Interface; I don't want them to be expanded to their full length and placed under ScrollView.
If you want to learn about ListView, here is a nice tutorial. About your question, here is the similar one! Your question might even be duplicate of this.
I don't think that putting multiple ListView/GridView objects inside ScrollView is a good idea.
The biggest advantage of ListView/GridView is that they reuse View's. When you scroll a ListView what the system really does is to use fixed number of views, and swaps the view settings (text, image source etc.). This is done by requesting the getView(int,View,ViewGroup) method from the list Adapter.
What you are trying to do is to force the ListView/GridView to render all it's raws, which pretty much beats the whole purpose of using ListView/GridView in the first place.
Use LinearLayout inside the ScrollView instead, and then add Views dynamically from your Activity/Fragment
Just specify dimensions to your ListView/GridView that are not all match_parent.
Also, if you want to proportionally allocate say 50% and 50% of available height to your list and grid, put them in a LinearLayout and use the layout_weight mechanism:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ListView
android:layout_width="match_parent"
android:layout_height="0px"
android:layout_weight="1"
... />
<GridView
android:layout_width="match_parent"
android:layout_height="0px"
android:layout_weight="1"
... />
</LinearLayout>
you can set the layout to include how many listViews and gridViews as you wish. just choose a layout and set their sizes yourself. if you put them in a linearLayout, you can set a weight for each of them, to make their width/height proportional to the layout width/height.
However, do note that the more you put, the more cluttered the UI is.
Also note that Google suggests to never put listViews and gridViews inside ScrollViews (this was being talked about on the "the world of listView" lecture) .
To allow users to submit comments, I have 2 views, vertically stacked. A ListView for displaying entered comments and a LinearLayout footer, for allowing the user to add a comment (which is basically an EditText and a button).
The footer must be anchored to the foot of the screen and the ListView must sit above it. Its similar to what you see on facebook for Android when you are adding comments.
However I don't want the ListView to initially take up the full space - I want it to take up only the space required to display its rows, but to be able to grow into the remaining space as the user adds comments - while always staying above the footer layout.
I've tried a LinearLayout as suggested here Android: How can you align a button at the bottom and listview above?
However, this results in the ListView taking up all the space above the footer - when there is only a couple of comments - so its mainly empty and looks weird.
I have tried a RelativeLayout parent, where the footer is anchored using android:layout_alignParentBottom="true"..... Positioning the ListView above the footer using android:layout_above="#id/footerLayout" forces the same behaviour as above (ListView takes up all remaining space)... removing this allows the ListView to 'grow' but it overlaps the footer if its grows too big.
Cheers.
I guess this workaround will work!
<LinearLayout
layout_width="MATCH_PARENT"
layout_height="MATCH_PARENT"
orientation="vertical">
<LinearLayout
layout_width="MATCH_PARENT"
layout_height="0"
android:weight="1"
orientation="vertical">
<YOURLIST
layout_width="MATCH_PARENT"
layout_height="wrap_content"
/>
</LinearLayout>
<YOURVIEW
android:layout_width="MATCH_PARENT"
android:layout_height="WRAP_CONTENT"
android:weight="0"/>
</LinearLayout>
I guess one way to do it would be using the android:fillViewport attribute in the XML. See this blog post by Romain Guy: http://www.curious-creature.org/2010/08/15/scrollviews-handy-trick/
I have a layout requirement like below,
Textview
TextView
ListView
Edit Text
Button
Since listview cannot fit in landscape, I want to have list view onwards (ie. listview, edittext and button) to be a scroll view.
I know listview cannot be used inside a scrollview, but is there a way to do that ?
Any working example will be appreciated.
99% of android developers think we should not use ListView inside a ScrollView because both are scrollbale views and only parent can be scrollable, so it wraps the ListView.
Its 100% correct. But we have to use tricks to avoid this and to achieve our requirements.
I found one trick in web, which is setting the height of ListView based on the list items. Just check the link below, you will get an example code to calculate the height of ListView to fit inside a ScollView.
Android ListView height calculation to fit in ScrollView
The problem with this code is the list view will be filled entire screen if more children are available.
You have to use below template to achieve solution to your requirement.
<ScrollView >
<LinearLayout vertical>
<TextView />
<TextView />
<ListView />
<EditText />
<Button />
</LinearLayout>
</ScrollView>
I saw one video on youtube, Android ListView inside a ScrollView which is showing we can limit the height of listview, can be scrollable and used inside a ScrollView. I don't know how the programmer achieved that.
I am also thinking to produce same result by avoiding above example code. I hope it may help you temporarily. Please let me know if you got solution.
The better solution for this kind of layout is that You should use relative layout and fix ur EditText and Button at the bottom of ur screen like i have in my list view(see the image below) so that you wont need to add ScrollView in ur layout.
Just do this
<ScrollView>
<LinearLayout>
<ListView>
</LinearLayout>
</ScrollView>
Then add your
EditText
Button
Sort of a round about way to do what you want to do without a scroll view.
Write a custom adapter for your ListView
Assume you have an array of n elements that you want to populate the ListView with and then the EditText and the Button. So number of elements will be n+2
In the getView for the position n+1 return a view which has an EditText box instead of the normal list item
For the n+2 position return a Button.
Don't try to wrap around a ListView with a ScrollView, you will need up with lot of issues.
Note: I have not tested this, not even sure if it will work. Do let me know if it works. :)
I want to put tow listviews in one scrollview on android platfrom to make both of them scrolling synchronized. For instance, when I drag the left listview up and down, the right side one would be scrolled as the same. I have tried to extend the scrollview for overriding methods but haven't get it work. Any advice will be appreciated.
If your two listview does not take many memory and has same height, try put them in single scrollview and let scrollview do scroll.
layout would be look like this:
<scrollview layout_width:fill_parent layout_height:wrap_content>
<linearlayout orientation:horizontal layout_height:wrap_content layout_width:fill_parent>
<listview layout_height:wrap_content layout_width:wrap_content layout_weight:1/>
<listview layout_height:wrap_content layout_width:wrap_content layout_weight:1/>
</linearlayout>
</scrollview>
In this case, you should set height of listview manually. you can find a solution here.
But if you use this solution, listview can't optimize memory usage, so listview can take much memory as item count increase.