Android ExpandableListView with Custom Adapter: BaseExpandableListAdapter

This tutorial describes how to use Android ExpandableListView with Custom adapter and in more detail BaseExpandableListAdapter. In the previous post we talked about ListView and how we can use it. Android OS has another widget that can be useful when you want to group items, this component is called Android ExpandableListView. This component has the capability to group items and when user clicks on the group it expands showing items.

android expandablelistview
This component can be used when we have a long item list and it can be divided in groups to organize them and make things less confused.

This component can be used when we have a long item list and it can be divided in groups to organize them and make things less confused.
expandablelistview_groups
When user clicks on the group it gets expanded and we have:
expandablelistview_item

As it is shown above, we need two different layout: one for the group and another one for items. So it is a little bit more complex than a listView even if the concept behind this component it is the same. We need to develop an adapter and two layouts.
Let’s suppose we have two classes that represent our model: one is the Category class and another one is the ItemDetail. Category holds a list of ItemDetail so Category class is like a Group (see above) and ItemDetail is an item.
Here there’s a code snippet:
public class Category implements Serializable {

private long id;
private String name;
private String descr;

private List<ItemDetail> itemList = new ArrayList<ItemDetail>();

...
}
public class ItemDetail implements Serializable {

private long id;
private int imgId;
private String name;
private String descr;
....
}

Now it is time to create our group layout. We will make it really simple: just two lines one for the Category name and the other for its description, so we have:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >

<TextView
android:id="@+id/groupName"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="15dip" />

<TextView
android:id="@+id/groupDescr"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_below="@id/groupName"
android:textSize="8dip" />

</RelativeLayout>

Now we need another layout for items so we have:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >

<TextView
android:id="@+id/itemName"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentLeft="true" />

<TextView
android:id="@+id/itemDescr"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_below="@id/itemName" />

</RelativeLayout>

We made things really simple. Now we have our layouts we need to create an adapter to handle items and groups and bind them together.

Android ExpandableListView Adapter

To create a suitable adapter for Android ExpandableListView, we have to extend BaseExpandableListAdapter. If you read the documentation about this abstract class you can notice we have to implement some methods. We could use SimpleExpandableListAdapter that implements some methods already, but we want to have a deeper control about our adapter.

There are two methods that are used to create the View corresponding to our layout, one for the items (childs) and one for the groups. These methods are:

View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) used when we need to create a child View
View  getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) used when we need to create our group View.

So we have to override these two methods so that we can use our layouts. There are other “helper” methods that we need to implement in order to know the total number of child (items in our case), the child ids, the total group (category) number and the group ids.
Let’s focus our attention on the getChildView first, here there’s the code

@Override
public View getChildView(int groupPosition, int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {

View v = convertView;

if (v == null) {
LayoutInflater inflater = (LayoutInflater)ctx.getSystemService
(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.item_layout, parent, false);
}

TextView itemName = (TextView) v.findViewById(R.id.itemName);
TextView itemDescr = (TextView) v.findViewById(R.id.itemDescr);

ItemDetail det = catList.get(groupPosition).getItemList().get(childPosition);

itemName.setText(det.getName());
itemDescr.setText(det.getDescr());

return v;

}

As you can notice in the method we receive the groupPosition and the childPosition this one specify the the child position inside the category (group). The code is quite trivial we simply inflate our item_layout and then we retrieve first the group inside the category list at groupPosition and then the child (ItemDetail class) inside the list held by Category class.

ItemDetail det = catList.get(groupPosition).getItemList().get(childPosition);

When we have to create a group View corresponding to our Category class we simply do the same thing, like shown below:

@Override
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {

View v = convertView;

if (v == null) {
LayoutInflater inflater = (LayoutInflater)ctx.getSystemService
(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.group_layout, parent, false);
}

TextView groupName = (TextView) v.findViewById(R.id.groupName);
TextView groupDescr = (TextView) v.findViewById(R.id.groupDescr);

Category cat = catList.get(groupPosition);

groupName.setText(cat.getName());
groupDescr.setText(cat.getDescr());

return v;

}

What about other methods?…Well they’re really trivial and we don’t need to explain them.

In the main activity the one that create our Android ExpandableListView we have:

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initData();
setContentView(R.layout.activity_main);

ExpandableListView exList = (ExpandableListView) findViewById(R.id.expandableListView1);
ExpandableAdapter exAdpt = new ExpandableAdapter(catList, this);
exList.setIndicatorBounds(0, 20);
exList.setAdapter(exAdpt);
}

In the code above we simply get the ExpandableListView widget reference in our main layout and create the Adapter. One thing you should notice is

exList.setIndicatorBounds(0, 20);

Using this method we set the indicator bounds. The indicator is the icon that is drawn near the group that change if the group is open or close. Here some images:

Image of a list of category

android_expandablelist_view_group

Image of items inside each category

android_expandablelist_view_item

Source code availabe @ github

  • Nice post.Give it up. Thanks for share this article. For more visit:android development

  • Anonymous

    thanks , nice article!

  • Rishabh Srivastava

    how to add sliding animation?

  • survivingwithandroid

    what kind of animation would you like to add?

  • Tububerry

    Can't thank you enough. It was useful. I wanted to see the customization for group and Item separately. This is what i wanted exactly.

  • valdo2

    how load bd in function initdata()?

  • survivingwithandroid

    What's bd? If you mean data you can download the source code at github and you can find how data is initialized. Let me know if the answer is what you are looking for.

  • valdo2

    tenxs, I need load the ExpandableListView with my BD. But i see function initdata() load records. Are you example o idea load records in the function initdata?. sorry for my bad english write. Regards

  • wildo

    how to delete the item from the list after I clicked it?

  • Siti Sumartie

    it really something new for me, i have to try this. so tips facebook want to say thanks so much

  • ahtsham

    i want to expand row using simple adpter on expandable ?help please

  • ahtsham

    i want to expand row using simple adpter on expandable ?help please

  • ahtsham

    i want to expand row by clicking buttton and using simple base adapter not expandable?can any body help me ?

  • ahtsham

    i want to expand row by clicking buttton and using simple base adapter not expandable?can any body help me ?

  • George Lyle

    You’ve not defined catList and you also defined itemList in the class for Category properties not Item properties.

  • George Lyle

    You've not defined catList and you also defined itemList in the class for Category properties not Item properties.

  • George Lyle

    Where did you define “catList” and why is itemList defined in the Category class?

  • George Lyle

    Where did you define "catList" and why is itemList defined in the Category class?

  • Can't you find it in the source code?

  • edekovacs

    Most interesting part is missing…

  • edekovacs

    Most interesting part is missing…