How to use the ExpandableListView in Android

Definition:
A view that shows items in a vertically scrolling two-level list. This differs from the ListView by allowing two levels: groups which can individually be expanded to show its children. The items come from the ExpandableListAdapter associated with this view.
http://developer.android.com/reference/android/widget/ExpandableListView.html

Intro

Ok, I’m going to try and explain to you the easiest way to implement a ExpandedListView in your android project. It took me nearly 4 hours to do all the research and get it fully working on an android device.

Let’s begin

Ok, let’s begin by creating a new Activity. I named my activity ProductsActivity. And your activity should extend ExpandableListActivity.

public class ProductsActivity extends ExpandableListActivity {

}

And before we start we have to create an ExpandableListAdapter.

private ExpandableListAdapter mAdapter;

Create your groups and children

Now, because my application has Categories and Products, I will also declare my categories and products.

private List<String> cats = new ArrayList<String>();

Then fill them with some content and flatten the ArrayList to a simple array. I simply prefer to use ArrayLists because they allow me to dynamically add data unlike a traditional Array. And I need to flatten them to a basic Array because you will see that my Adapter only accepts basic Arrays.


cats.add("Alcoholisch");
cats.add("Non-Alcoholisch");
cats.add("Eten");
String[] categories = cats.toArray(new String[cats.size()]);

Now comes the tricky part. I’m going to create a List inside a List. (nested lists)
I’s basically just 2d array, but dynamic because Lists can add items without the need to resize them.

List<List<Product>> list = new ArrayList<List<Product>>();

Now that’s done, I can start filling the List with Lists of Product.


List<Product> alcohol = new ArrayList<Product>();
 alcohol.add(new Product("Jupiler", 1));
 alcohol.add(new Product("Palm", 1));
 alcohol.add(new Product("Duvel", 2));
 list.add(alcohol);

List<Product> frisdrank = new ArrayList<Product>();
 frisdrank.add(new Product("Cola", 1));
 frisdrank.add(new Product("Fruitsap", 1));
 frisdrank.add(new Product("Water", 1));
 list.add(frisdrank);

List<Product> eten = new ArrayList<Product>();
 eten.add(new Product("Hamburger", 2));
 eten.add(new Product("Hotdog", 2));
 list.add(eten);

Again, we will have to flatten these nested Lists to a standard 2d Array. (Because my custom Adapter uses 2d arrays and not nested Lists) Luckily there are multiple libraries that can do this.
I’m using Transmorph to do this. Using this Library it’s extremely easy to convert the nested Lists to the required 2d Array.

Transmorph transmorph = new Transmorph(new DefaultConverters());
Product[][] products = transmorph.convert(list, Product[][].class);

Create your own ExpandableListAdapter

Now, I will create my own ExpandableListAdapter. I will not explain how to do this, simply copy/paste the following code. (If you wish to learn more about creating your own ExpandableListAdapter, I suggest you read the Android documentation)

  public class ProductExpandableListAdapter extends BaseExpandableListAdapter {
    // Sample data set.  children[i] contains the children (String[]) for groups[i].

    private String[] groups;
    private Product[][] children;

    public ProductExpandableListAdapter(String[] groups, Product[][] children) {
      this.groups = groups;
      this.children = children;
    }

    public Object getChild(int groupPosition, int childPosition) {
      return children[groupPosition][childPosition];
    }

    public long getChildId(int groupPosition, int childPosition) {
      return childPosition;
    }

    public int getChildrenCount(int groupPosition) {
      return children[groupPosition].length;
    }

    public TextView getGenericView() {
      // Layout parameters for the ExpandableListView
      AbsListView.LayoutParams lp = new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 64);

      TextView textView = new TextView(ProductsActivity.this);
      textView.setLayoutParams(lp);
      // Center the text vertically
      textView.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
      // Set the text starting position
      textView.setPadding(36, 0, 0, 0);
      return textView;
    }

    public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
      TextView textView = getGenericView();
      textView.setText(getChild(groupPosition, childPosition).toString());
      return textView;
    }

    public Object getGroup(int groupPosition) {
      return groups[groupPosition];
    }

    public int getGroupCount() {
      return groups.length;
    }

    public long getGroupId(int groupPosition) {
      return groupPosition;
    }

    public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
      TextView textView = getGenericView();
      textView.setText(getGroup(groupPosition).toString());
      return textView;
    }

    public boolean isChildSelectable(int groupPosition, int childPosition) {
      return true;
    }

    public boolean hasStableIds() {
      return true;
    }
  }

Set the adapter

We’re almost done, all we have to do now is set the list adapter.

mAdapter = new ProductExpandableListAdapter(categories, products);
setListAdapter(mAdapter);

And we’re done. We can now see our list with our categories and it’s products.

~Michiel De Mey

Michiel De Mey

Full-time geek, Full Stack Engineer and Full Metal Hero. NodeJs, AngularJs, API design, WebSockets, WebSec & IoT enthusiast. Former San Francisco resident.

More Posts - Website - Twitter - Facebook - LinkedIn - Google Plus