How to use a ListView inside a ExpandableList? - android

I've been working with a custom ExpandableList (see example picture below) where each item always has one child. This child consists of three parts. Each part has a header (red bars) and below that an Empty item OR a list of items. The length of this list will vary.
The first way I tried to do this is by adding a ViewStub below the empty item, which I inflated with a custom view, which also contained a ViewStub at the end which I inflated in turn for the next item, thus adding items recursively to create this sort of list of items. Sadly this resulted in StackOverflowError's when the list became too long (With short lists this worked perfectly).
So on my second try I tried using a ListView with a custom adapter instead. Sadly this list only used a small part of my screen and the rest of the items where occluded behind the header of the next part (This mini list looked scrollable as a second scrollbar appeared next to it, but it did not scroll. Not that I would consider this scrolling inside a scrolling list to be a good solution, but just wanted to mention this).
Can anyone tell me how I can tell this list of items to not be scrollable and take up all the room that it needs (does it know what size it is going to be when the child node is created??) or help me with a alternative solution to my problem? (Ooh, and I have considered putting an unholy amount of ViewStubs inside my layout, but that just seems idiotic and really bad practice. Correct me if I'm wrong)

If I understood you correctly, then why don't you just take an ExpandableList + Adapter that implements ExpandableListAdapter? It's a somewhat ugly approach but it works and isn't much hassle.
MyAdapter implements ExpandableListAdapter
#Override
public View getChildView(int groupPosition, int childPosition,boolean isLastChild, View convertView, ViewGroup parent) {
}
In this method you could simply figure out if the current childPosition would be one of the headers or one of the children and inflate the appropriate View from xml.

Related

Android: What’s the best way to implement the BaseAdapter if item content in ListView is dynamic?

In most case, we need to implement the BaseAdapter’s getItemViewType() and getViewTypeCount() for dynamic item content of the listview, as this post says. But I think this solution is only suitable for finite number and knowing beforehand, such as listview item with sending layout and receving layout.
What about the case that the listview with its item content impossible knowing beforehand?
For example, I need to show a contact list from server, the contact list size is about several thousand. For each item, I need to show, for example, the hobby “list”. It is a small range of 0 to tens of string. So in this case:
The item types is relatively bigger than normal case using “getItemViewType”
Though each item may be different, but similar to a certain degree: the item content is different in the number of views, but common in view type. Item A is different from item B only because it have more TextViews.
For each time in the getView, the convertview is hard to simply reuse because they are different, but if we create new TextView and added to the convertView, it will impact the scrolling of the listview. I don't think it's appropriate such way. What should i do in such case?
Unfortunately you cannot easily change the number of item view types on the fly. The getViewTypeCount() method is only invoked when the adapter is set on the ListView. That means, were you to dynamically change it, then you would have to call setAdapter() again. This is a huge performance hit as the ListView will toss out all the recycled views and re-generate everything from scratch again.
Honestly, it looks like you should be using an ExpandableListView instead. It allows you to displays lists of items under groups. The only difference is the groups are placed on top of the list. So where you have A, B, C, D on the left side in your picture...in the ExpandableListView it'll sit on top.
The ExpandableListView can easily handle your situation where a given grouping could have any variable number of items within it. You mentioned needing to store a contact list. I'd suggest taking a look at a RolodexArrayAdapter for use with the ExpandableListView. It may be of help.

Better way for header in ListView

I want to show a fairly complex header above an ExpandableListView. The header basically holds some artwork and some text. When I scroll the List I want the header to scroll off the screen.
I can do it by adding a section to the list view with no children but it makes my BaseExpandableListAdapter very clunky. does anyone know of a better way. I've tried adding the header in the xml before the ExpandableListView tags but that makes it static at the top of the page when I scroll the ExpandableListView.
if you do not like native View header http://developer.android.com/reference/android/widget/ListView.html#addHeaderView(android.view.View) you can inflate special view and return it in the first position in your Adapter.
Actually we make adapter to control getting view in our ListView. So you can always return special views in special positions and for me that is ok. Not always view in your ListView must be similar. You just need to implement some populating logic for all this views.
Good luck!

Fully expanded nested lists - Android

I am attempting to create a nested list view for an android app. What I essentiall want is some thing like
nested list entry 1
Outer List Entry1 nested list entry 2
nested list entry 3
nested list entry 1
Outer List Entry 2 nested list entry 2
nested list entry 3
Where I have an outer list, which has two entries, and then have a nested list view which has detailed entries (if you imagine a calendar that has days of the week as the outer list, and with each day there is a list of 0 or more appointments listed vertically as above). Further more, I want the nested list items to be clickable/highlighted in the same way a top level list would be.
Most info I find having looked for nested list views is suggestions to use ExpandableListViews - Which I implemented, but it seems like a bit ugly to use this as its clearly not the same purpose (I dont want anything expandable - everything should always be fully expanded and non-collapsible - also, couldn't find info on laying out horizontally as above rather than vertical - but I assume that is possible relatively easily?).
I also used the selected answer here: android nested listview which works ok in terms of presentation, but doesn't offer the same list scroll/highlighting/click behavior for each individual item in the nested list.
Can anyone suggest any alternatives? ever implemented a similar layout with either of the above?
UPDATE
I want the layout of the lists to actually be like the above text representation - in an attempt to clarify the layout I want, here is an image (yes, I know I should probably be downvoted for the lame screenshot of a diagram in open-office :)
So you can see, I actually want the screen to look like that - the parent/outer list being a list of time periods (in this case its days of the week, but it could be hours of the day etc), and for each row in that outer list, I want the inner list (appointments for that given timeslot) to appear as a nested list aligned horizontally to the parent.
To make ExpandableListView not collapse ,use
expandableList.setOnGroupClickListener(new OnGroupClickListener() {
#Override
public boolean onGroupClick(ExpandableListView parent, View v,
int groupPosition, long id) {
return true; // This way the expander cannot be collapsed
}
});
Updated answer:
If you want a table then you should probably split it to Fragments.
The root View should be ScrollView.
The child must be horizontal LinearLayout
Every next column is a Fragment.
Every Fragment container should have some weight.
Every Fragment's root view should be vertical LinearLayout
Make sure Frament with days item has the height of exactly three "tasks" item height.
Hardcode them in dimen.xml.
For convinience, make every Fragment's LinearLayout extended class that can have ListAdapter set. Populate the every row based on ListAdapter.
That way you can achieve a list with fixed content.
Or you can do without Fragments if you don't want to be flexible.
Adding new column will be just a matter of Fragments that encapsulate the logic.

why does the ViewHolder pattern work?

I learned Android's ArrayAdapter today, and find there is a commom pattern which uses a ViewHolder to hold Views' reference instead of calling findViewById everytime.
But how does it work? Adapter is usually used to display a list of View(Group)s, If I cache the View, why don't they all reference to the oldest one?
If you want the best explanation on how the ViewHolder works, check out Romain Guy's Google I/O 2009 talk in youtube , specially the first 15 minutes.
In short, the Adapter functions as a link between the underlying data and the ViewGroup. It will render as many Views as required to fill the screen. Upon scrolling or any other event that pushes a View is out of the screen, the Adapter will reuse that View, filled with the correct data, to be rendered at the screen.
The getView(int pos, View view, ViewGroup parent) method will use the right View at any time, regardless of your layout. I do not know the internals of this, but I'm sure you can browse the source code for any adapter (such as ArrayAdapter.java) if you're interested.
The ViewHolder just keeps a pointer to the Views as obtained by view.findViewById(int id). It is the Adapter responsibility to return the right data corresponding to any position.
Slides 11 to 13 of Romain's presentation will make it a lot more clear than anything I can write.
Sorry but denis' answer may be wrong.
In fact, the view instances(and ViewHolders) are as many as your screen can display.
If your screen looks like:
[list view]
the first item
the second item
the third item
the fourth item
You will have 4 instances of views. If you scroll screen, the first will disappear but be pass to getItem() as convertView for you to create the fifth item.
So you can use the references in first ViewHolder.
I believe the work beneath the list view is something like this (considering we have only one item view type):
do once:
inflate item view from layout, cache it
repeat for every item:
ask adapter to fill the data into the view
draw the view on the screen
move to next item
so you have the view which is inflated from xml layout and can be reused for drawing multiple list items. ViewHolder speeds it up a bit more by saving getViewById lookups.

Adding multiple views to a listview

I tried to add these views to list view using this kind of factory but everytime I try and add the view to a ListActivity, it comes up with nothing. What am I doing wrong? I set my list views like so:
List<View> views = new ArrayList<View>();
for(int x =0;x<tagg_views.size();x++){
lv.addHeaderView(views.get(x));
}
It looks like you are trying to add x number of headers to your ListView. That doesn't make sense.
A ListView should contain x number of copies of the same view, with different information on each line.
Hello ListView gives a good example of the correct usage of a ListView.
Why are you adding the Views to the list yourself? I would highly recommend using any kind of apropriate Adapter for the List. The adapter will handle the creating and recycling of views while the user is scrolling etc. If you use an Adapter it is discouraged to save references to the view yourself like you are doing it in the views list.
The addHeaderView method you are using is made to one single header to the list that always will appear on the top of the list. This means calling it in a loop will not have a reasonable result.
Look into the helloListView example Mayra mentions to understand how a list in android is working. To see how a custom listadapter works have a look at this tutorial looks promising despite the bad code formatting.
A ListView is linked with and Adapter. The Adapter is responsible for the data displayed in the ListView. Take into account that internally ListView creates a pool of itmes (or a pool for each type of item that can be displayed in your case).
For this purpose your adapter needs to implement the following methods:
int getItemViewType(int position): Get the type of View that will be created by getView(int, View, ViewGroup) for the specified item. So you need to identify you types.
int getViewTypeCount(): Returns the number of types of Views that will be created by getView(int, View, ViewGroup). This is used to create a pool for each type of item.

Categories

Resources