Thursday, June 9, 2011

Hiding group indicator for empty groups

Another topic that keeps returning on this blog is the expandable list view. It seems those troublesome expandable lists always have some surprises in store. This time I ran into the issue of group indicators and empty groups.

Group indicators are those small arrows in front of the group rows that indicate, whether the group is expanded or collapsed. Trouble is that those indicators are always visible, even if the group is empty. This misleads users who think that they can expand the group. The group indeed expands but as it is empty, no child rows appear which can be extremely annoying.

Some internet sources propose wizardry with the variable drawable that backs the group indicator. If you follow the advice, the group indicator will disappear for all the collapsed groups (even for those which have child rows). This surprising behaviour is by design. Comment in the source of ExpandableListView says: "[if] the group is collapsed so we consider it empty for performance reasons". The method where this behaviour is wired in is private, it is not possible to overload it by subclassing ExpandableListView.

Click here to download the example program.

Fortunately the solution is very simple, even if a bit tricky. We will completely disable the group indicator logic in ExpandableListView and provide our own indicator from the adapter backing the expandable list. The group indicator is disabled by setting it to a transparent color in main.xml.

android:groupIndicator="@android:color/transparent"

Then we override getGroupView in the adapter (this time it was a SimpleExpandableListAdapter but the method works for any adapter). We had to manually add an ImageView to the group layout - this is normally done automagically by ExpandableListView but we have just disabled that functionality. Once getGroupView returns the group row, we post-manipulate the ImageView that acts as group indicator considering the child count for the group beside its expanded/collapsed state. This unfortunately means that you have to have custom expanded/collapsed icons in your program - those icons are extremely ugly in the example program, I leave it to you as a homework to beautify them.

15 comments:

DZONEMVB said...

I'm a community leader on a network of developer websites.  I really liked your blog content and thought you might be interested in some extra exposure on our sites.  Send me an email at ross [at] dzone [dot] com and I can explain all the details.

bengwade said...

Can you repost this example using an xml resource to store the group and child data? That would really help with putting together large lists. Thanks!

Anonymous said...

Thanks a ton. It works. A bit tricky as I am a newbie but it worked. Thanks.

Anonymous said...

Hi...I have noticed something. When a group is expanded the maximize icon is shown but when I scroll to the expanded group using mouse or HTC sense the icon changes to minimized icon.

Anonymous said...

This is a great program, but I cannot get the second tier indicators to be transparent. Could you upload some completed code with the fixes for the indicators? Or maybe post snippets so I know exactly what to change? I would appreciate it.

Gabor Paller said...

Anonymous, why would you want the second tier indicators to be transparent?

Anonymous said...

Yes, I would. Transparent or @null would be fine, just can't figure out how to do it.

Anonymous said...

Any chance of that code getting updated? It would be apprecaited!

Gabor Paller said...

Anonymous, I don't understand your problem. This code has no second tier indicators, it's a simple expandable list. What are those second tier indicators that you want to make transparent?

Anonymous said...

Perhaps my word choice is poor. I'm looking for a solution to your last paragraph:

"...Once getGroupView returns the group row, we post-manipulate the ImageView that acts as group indicator considering the child count for the group beside its expanded/collapsed state. This unfortunately means that you have to have custom expanded/collapsed icons in your program - those icons are extremely ugly in the example program, I leave it to you as a homework to beautify them."

I don't follow. Even after I make the first arrow transparent, I can't get the send group's arrow transparent.

Anonymous said...

send = second :S

Gabor Paller said...

Anonymous, what was the image that you made transparent? res/group_row.xml refers to expander_group drawable which is a variable image (in res/drawable/expander_group.xml). This variable image forks to two real images based on open/closed state, expander_ic_maximized.png and expander_ic_minimized.png. Which one did you change?

Unknown said...

Can do this in your 3 level expandable list example?
I wanna do this for the second level, but it isnt xml for the expandable list of the 2nd level

Gabor Paller said...

Ricardo, the 2nd level expandable list views are created in ColorExpListAdapter, in this line:

DebugExpandableListView dev = new DebugExpandableListView( context );

The adapter is set 2 lines down.

Mihir Trivedi said...

It works for me thank you....