Expandable lists

  • Written by  Clive

Double up: using expandable lists

Android ExpandableListView expandableList icon

Expandable lists let you create lists within lists.

They’re ideal for list items that have sub-categories. The user selects an item from a scrollable list and another list pops open. They can then make another selection from this list.

Our tutorial app

Our tutorial app displays a list of three country names. These are the parent items. The user can then select either of these to display a list of city names. These are the child items.

We display a Toast message when the parent item expands and when it collapses. Selecting one of the child items displays another Toast message indicating which country and city was selected.

Android ExpandableListView screenshot

Selecting an item from the parent list expands a child list

Here’s how we created our expandable list

Let’s start off with the layouts.

One layout to rule them all: The main layout

The activity_main.xml layout resource file has a vertically orientated LinearLayout as its root element. This layout contains the ExpandableListView container.

The ExpandableListView displays a vertically scrolling two-level list.

Visually, there are two lists:

  • The group or parent list displaying the country names
  • The child list displaying the city names

Here’s the code for our ExpandableListView:

Android ExpandableListView

The ExpandableListView view displays the two-level list

A quick explanation

The divider attribute is set to display a green colour while the dividerHeight attribute sets the height of the band to 10 pixels.

The indicatorLeft attribute sets the left bound for the expandable indicator. We use a system value here which is 3 dips.

The active theme will determine what the indicator will look lake. You can supply your own indicator using the groupIndicator attribute.

One layout for the parent item’s TextView

The country name is displayed in a TextView in a group or parent view within the ExpandableListView. You’ll find this TextView in the parent_layout.xml resource file.

Here’s how we define it in the layout file:

Android ExpandableListView group view parentLayout

The group item TextView layout

A quick explanation

This text view is used to display each of the country items in the parent list.

We set the top and bottom padding to 10 pixels and use one of the system’s padding values for the left padding (40 dips).

We set the textAppearance attribute using the system’s large text appearance value. This sets the text’s size, color and style to ensure that the text will look the same on all devices. However we override the color and text style attributes by supplying our own values.

One layout for the child item’s TextView

The city name is displayed in a TextView in a child view within the ExpandableListView. You’ll find this TextView in the child_layout.xml resource file.

Here’s how we define it in the layout file:

Android ExpandableListView child view childLayout

The child item TextView layout

A quick explanation

This TextView is used to display each of the city names in the child list.

We use the background attribute to set the view’s background to orange and center the text in the view using the gravity attribute.

We set the top and bottom padding to 10 pixels.

We set the textAppearance attribute using the system’s large text appearance value. This sets the text’s size, color and style to ensure that the text will look the same on all devices. However we override the textColor attribute, setting it to white to make the text visible against the orange background.

So where’s the data?

Our data is stored in three String Arrays in our MyDataArrays class.

We use another class, MyDataProvider to load the arrays into a List and then put the lists into a HashMap. Calling the MyDataProvider’s getDataHashMap() method returns the HashMap.

We can then use the HashMap to get the country and city names for our expandable list.

Making the connection: The adapter

We use an adapter to link the data to the list views.

We create our own custom adapter by extending the BaseExpandableListAdapater class.

There are a number of required methods that you have to implement. We’ll only discuss three of them:

  • getGroupView() – gets a view to display the given group (our countries)
  • getChildView() – gets a view to display the given child (our cities) within the given group (our countries)
  • isChildSelectable() – used to make the child views (cities) selectable

Let’s look at our custom adapter’s code:

Constructing the adapter: The constructor

Android ExpandableListView ExpandableListAdapter custom adapter constructor

Pass the context, the HashMap and the HashMap keys to the constructor

A quick explanation

We pass three parameters to the constructor:

  • The context
  • The HashMap containing the lists of countries and their cities
  • A list containing the keys to the HashMap

Showing the items: The views

One view for the group

This displays each of the parent views (in our case, the countries) in the ExpandableListView.

Android ExpandableListView ExpandableListAdapter custom adapter getGroupView()

Use the getGroupView() method to get a view to display the group list items in the expandable list

A quick explanation

We pass four parameters to the getGroupView() method:

  • The position of this view (country) in the parent list
  • Whether this view is expanded
  • The old view to reuse if possible. If it doesn’t exist then we’ll create it by inflating the parent_layout.xml layout file into the parent ExpandableListView
  • The parent ExpandableListView
  • groupTitle – we call getGroup(), passing the position of this item as a parameter, to get this group item (country)
  • we use an if statement to check if an old convertView exists, if it doesn’t then we create one by inflating the parent_layout.xml layout file into the parent ExpandableListView
  • parentTextView – we get a reference to the parent TextView which we will use to display this country item in the parent or group list
  • we call setText() to display the country item
  • we return the view to display this country item in the list

One view for the child

Android ExpandableListView ExpandableListAdapter custom adapter getChildView()

Use the getChildView() method to get a view to display the child list items in the expandable list

A quick explanation

We pass five parameters to the getChildView() method:

  • The position of the group (i.e. country) that contains this child view (city)
  • The position of this child (the city) within the parent group (the country)
  • Whether this is the last child in the group
  • The old view to reuse if possible. If it doesn’t exist then we’ll create it by inflating the child_layout.xml layout file into the parent ExpandableListView
  • The parent ExpandableListView
  • childTitle – we call getChild() to get the city. We pass two parameters:
    • the position of group that this child is a member of
    • the position of the child within the group
  • we use an if statement to check if an old convertView exists, if it doesn’t then we create one by inflating the child_layout.xml layout file into the parent ExpandableListView
  • childTextView – we get a reference to the child TextView which we will use to display this city item
  • we call setText() to display the city item
  • we return the view to display this city item in the list

Make the child items selectable

We use the isChildSelectable() method to return true, so that we can select the child (city) items.

You may want to check out our tutorial on Adapters: What are Adapters?

Show me the money! The Activity

The MainActivity activity inflates the activity_main.xml layout file to display the expandable list.

Here are the most important lines of code for displaying the expandable list:

Android ExpandableListView ExpandableListAdapter activity setAdapter()

Get the view, get the HashMap and keys, create the adapter and show the list

A quick explanation

We get a reference to the ExpandableListView, expandableListView.

Then we call MyDataProvider.getDataHashMap() to get the HashMap containing the lists of countries and cities. We assign this to our HashMap, countriesHashMap.

Next we create a new ArrayList, countriesHashMapKeys and load it with the HashMap’s keys.

Then we create a new instance our custom ExpandableListAdapter, by passing context, countriesHashMap and the countriesHashMapKeys to its constructor.

Finally we call setAdapter(), passing our new adapter as the parameter, to set the adapter.

Choose one or two: Handling the selections

You can choose a group item or a group item plus a child item.

We use listeners to listen for when any of the list items are selected.

  • OnGroupExpandListener – listens for when a group item (country) has been selected. Once selected, it expands and triggers its onGroupExpand() method
  • OnGroupCollapseListener – listens for when an expanded group item (country) has been selected. Once selected, it collapses and triggers its onGroupCollapse() method
  • OnChildClickListener - listens for when a child item (city) has been selected. Once selected, it triggers its onChildClick() method

In all cases we display an appropriate Toast message.

If you’re interested, have a look at our Toast tutorial, Making Toast where we show you how to use the Toast widgets to display messages.

You may also find our ListView tutorial, Android ListView tutorial, helpful.

Android's ExpandableListView not quite what you want? Have a look at these ExpandableListView libraries:

Thanks to Prabeesh R K for a great youtube tutorial that inspired me to publish this one. 

I hope that you have found this tutorial helpful.

This project was created using Android Studio.

You can download the project files here Download icon

Are you using Eclipse or another IDE? Here's how you can use this project's Android Studio files.