December 22nd, 2012

Android Tricks: Expandable ListView Items

The Android notification subsystem was significantly revamped in Jelly Bean. Among the new features, notifications can now be presented in two modes—collapsed and expanded. The user can toggle between the two modes by using a 2-finger swipe gesture, dragging up or down on the item in the notification panel. The GMail notification uses this new feature to present a summary of the new emails received in expanded mode while only giving a count of new mails in collapsed mode:

GMail in the Android notification panel (Credit: The Verge)
GMail in the Android notification panel Image Credit: The Verge

I wanted to provide a similar effect in one of my own applications, allowing items in a particular ListView to similarly expand and contract. In my application, there is a list that displays a map image generated with the Google Static Map API in each row. Downloading and instantiating the map image for each row turned out to be very costly and prevented fluid scrolling. That problem led me to the idea of having two modes for the list item—the map image is only instantiated when needed, after the item is expanded.

The code to support the expanding item is not available as a public API in the framework, so I ported the underlying Java code over to C# and integrated it with ListView to replicate the behavior. I published the three-part code implementation in this Gist on GitHub: https://gist.github.com/4333318

ExpandableListView is the type that you use to incorporate the control into your own application. You also need to download and put in your resource directory the following two images from the Android framework to provide the glow.

I use a custom ActivityItem view as my ListView row, which is instantiated from an XML layout containing the following item. When used, the item can be collapsed and expanded. It will start in the collapsed state, as the layout_height property indicates.

<ImageView
    android:layout_width="fill_parent"
    android:layout_height="0px"
    android:id="@+id/MapPicture"
    android:scaleType="centerCrop"
    android:layout_marginLeft="1px"
    android:layout_marginRight="1px" />

The map is only downloaded when the helper class marks that the row has been expanded for the first time, allowing us to reduce the overhead of using map images. The following images show the result of a normal, downward 2-finger swipe: