Click here to download the example program.
Our three-level list is a variation of an earlier example program but I inserted another level (somewhat without reason :-)).

The principle of the implementation is simple. The first-level list is backed by an ExpandableListAdapter. The child views generated by this adapter are ExpandableListAdapters themselves that provide the second-level groups and the eventual child elements. Listeners are set for the group events (expand/collapse) of the second-level lists. When a group event occurs on a second-level list, the layout of the first-level list is also recalculated to accomodate for the size changes of second-level expandable lists.
This sounds simple but there are some tricky points that made me spent more time on this prototype than I expected. The first issue is with the individual rows of the second-level lists and the view recycler. Check out getChildView() in ColorExpListAdapter.java. When the layout of the list is recalculated, the old views are offered to the list adapter for reuse. The getChildView() method gets the old view instance in the convertView parameter. If convertView is not null, the adapter has the option of reusing the old view instance. In this case the adapter does not instantiate a new view but sets the old view instance appropriately, decreasing garbage (Click here if you want to read more about the importance of less garbage collection in mobile environments). Now our problem is that we cannot just set up an ExpandableListView instance without destroying its internal state, i.e. the expanded/collapsed state of the groups. For this reason, it is extremely important to preserve the views and to prevent the first-level ExpandableListView of rearranging the second-level lists (handing out a second-level ExpandableListView in a certain position as a convertView at a different position). For this reason I implemented a cache in ColorExpListAdapter that makes sure that only one second-level ExpandableListView is generated for each child position in the first-level list and that second-level ExpandableListView instance is consistently returned for the same position. This guarantees that the collapsed/expanded state of the second-level views are preserved when the layout of the first-level list is recalculated.
The other tricky issue is the size of the second-level lists. The layout recalculation of the first-level list is triggered by a group event of a second-level list. Due to the way expandable lists are implemented, when this event occurs, the items of the second-level list which was clicked are not yet added/removed according to the expand/collapse action. This means that the size of the list will be incorrect when the first-level list layout is recalculated.
To solve this problem, observe the row count calculation in ColorExpListAdapter's calculateRowCount method and the way the row count is used in DebugExpandableListView's onMeasure method. DebugExpandableListView originally started to exist so that I can observe the layout of the second-level lists then it turned out that it has an important function: override the onMeasure method of the original ExpandableListView (actually inherited from ListView). Lazily, I kept the class name and the debug messages in it so that you can observe the rather complex operation of the layout process if you feel like.
40 comments:
The code doesnt seem complete. When checking there is a reference to the method "getExpandableListView()" when creating a new adapter in OnCreate() but I cant find that method. Also cant find the method setListAdapter.
Anything I have done wrong or is it something that is missing?
//TitanSky
TitanSky, those methods are inherited from ExpList3's base class, ExpandableListActivity (fully qualified name is android.app.ExpandableListActivity). Does the code compile correctly? (I have just tried, it does for me)
Nice blog. I'm just getting started with some Android development so will check your blog often
Well, i have situation like this i hope you are definitely going to help me..i want to replace all the strings in 2nd levels's content i.e #D3D3D3, #696969, #EAEAEA,#1C86EE...etc with check boxes and implement on-click listener for those contents for checking whether corresponding check box is checked or not..hope you got me..
vgsl-manju, there are two posts about this situation this is the second and the first one is linked from it. These posts build on each other, read both.
can i have code for dynamic expandable list view
sri, you may want to check this post.
First of all thanks a lot, your tutorial helped me a lot.
Now i wanted to know if groupview has no child then there should not be a icon or there should be a empty icon. How to do the same?
Anonymous, do you mean that if there is no entry for a certain second-level group then there should not be an expansion icon on the first level either?
How can i add list view as child?? i would like to add n number of expandablelistview depending on the requirements..any suggestions on how to do this.
In your example you have specified the size of the array ...i dont want to hardcode that value but would rather change depending on the tree size.
Thanks for the great tutorial. Can you please tell me how can i make a n level tree?
Thanks
J
Good code man.Nice blog.
www.androidcookers.co.cc
Good tutorial, but I'm having some trouble I hoped you might have some thoughts on. My array of values isn't static, it's based of off some html parsing. I can't figure out how to populate the contents[][][][] string array with my data. In my content, h1's and h2's are my groups (respectively), and the rest of the stuff is the 'colors'.
How can we handle click of last child?
Thank you very much. I've been struggling very much the whole day. I got everything hooked up but the children were not getting aligned properly. I stumbled upon this and that one magic line which has been evading me all day:
v = inflater.inflate(R.layout.group_row, parent, false);
I was specifying the wrong parent.
Thank you! I really appreciate it.
Excellent pieces. Keep posting such kind of information on your blog. I really impressed by your blog.
Thank you very much for the post. I have question how customize group indicator at second level? I wan to disable group indicator at second level. I am able to add image there but could disable default indicator at second level.
Thank you very much for the post. I have a question how to customize group indicator at second level? I want to disable group indicator at second level. I am able to add image there but i am not able to disable default indicator at second level.
Rakesh, does this post help?
Yes, Gabor paller this post helped me. i got answer for the question i asked...Now iam try to set click listener to child view of level 2
I want to create multi level list view for my Product category. But i seem that your example fix level 1 and 2. There isn't any way to do it more general,is it? I get stuck now. I hope you will reply soon
Linh, I am not sure 3-level lists are such a great idea. For me, even 2-level lists are somewhat confusing. But you can use the same concept as used in this example program: embed expandable lists as child views of upper-level expandable lists. Then you can create expandable lists of any depth.
All right, i will try thinking that way. Thank you so much.
First of all, nice code! gz! Your post helped me a lot, thank you.
I have a question regarding the child node. Lets say that I want to start a new activity from the child row selection. Im aware of the onChildClick() method but Im having trouble to adapt it to your code. Could you throw me an example?
how can i add Upto 4 level expandable treeview in Android. I try this code but not add fourlevel plz help me
thanks
Rupal, just follow the example, it is easy. You have to add another expandable list views as children of the second-level expandable list views.
i try but not solve plz hel me
i try but not done plz help me how to add 4-level in Expandable listview
Hi,
Excellent tutorial.But i want to set different heights for my child 1 and child 2.How can i do it?plz help...Thanks in advance
Rupal, here you are.
But don't come with new requirements! :-)
Anonymous, there you find the following line in DebugExpandableListView.java:
Method:
onMeasure
setMeasuredDimension( getMeasuredWidth(), rows*ROW_HEIGHT );
As you can see, this simple program calculates every row with the same height. You need to implement more sophisticated logic here to support rows with different height.
can we implement checkbox with each group subgroup and child.. please help.. because i am developing tree structure with checkbox on the right side of each element.. and if checkbox can be implemented how to implement oncheckedchange listener on each checkbox..
thank you for the code,it helps me a lot... But the scroll view is not working properly,, the child items in the third level are not scrolling,,, once check it please.... Thanks in advance
krishnaveni, you mean that you added a scroll view to the third level? I never tried that.
Hi, i want to know if with your code i could create an infinite lvl expandablelistView ? i want to make a file explorer using this method.
In the getChildView i will return another expandablelistview if the file is a directory.
If you can help me answering by email
Hi I am trying to implement a expandable list with edit text and text views as child elements.In short I want form elements as child elements of group like edit text ,spinner etc .Please help me to implement this kind of code
Hello,
Thanks for your explanation. I tried it and it goes fine.
I would like to adapt this to dynamically calculate the height of the "embedded" ExpandableListView because all the rows within it could have different height... So i can't count the number of rows and set "height = count * row_height".
I tried to getHeight() from each getChildView() and getGroupView() of my adapter but 0 is always returned...
I think it's because :
"Be aware not to call getWidth() or getHeight() too early before the view have been laid out on the screen, otherwise "0" will be returned."
Any idea of to fix that ?
Hi, is there anyway to create expandable list with different layout for each group, and different child layouts according to their parents.
How you define the ROW_HEIGHT in DebugExpandableListView. Where did you get this number?
Post a Comment