Android Expandable ListView Tutorial/Example

ExpandableListView allows the user to expand grouped set of items.Items are like ListView which are expanded when user click them.

Expandable ListView is used to categorize the data and a better to represent grouped data.

So Start building your Expandable Listview Sample.

1.Open Eclipse or Android Studio -> New Project->Android Application Project-> Name of Application-> Follow all instructions and complete by clicking on Finish.

2.For creating Expandable ListView we need three layouts one for the main screen contain expandable listview, second for headers which will be expanded and third for header’s items which be shown on header’s expansion.

//layout for mainactivity

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent"
    android:layout_height="match_parent"                 android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">

<ExpandableListView
    android:id="@+id/expandlist"
    android:layout_width="match_parent"
    android:layout_height="match_parent"></ExpandableListView>

</LinearLayout>

//layout for headers which will expand or collapse

listview_header.xml

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

    <TextView
        android:id="@+id/expandheader"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textSize="25dp"
        android:paddingLeft="?android:attr/expandableListPreferredItemPaddingLeft"
        android:textColor="@android:color/black"/>
</LinearLayout>

// layout for header’s items which will be visible on click of header’s

headers_items.xml

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

    <TextView
        android:id="@+id/headeritem"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="20dp"
        android:padding="5dp"/>
</LinearLayout>

3.Create Custom Adapter class by extending your adapter class to BaseExpandableListAdapter  like as follows

MyExpandableAdapter.java

package com.coderzpassion.expanlistsample;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.TextView;

import java.util.HashMap;
import java.util.List;


public class MyExpandableAdapter  extends BaseExpandableListAdapter{
    private Context con;
    private List<String> headers;
    private HashMap<String,List<String>> headeritems;

    public MyExpandableAdapter(Context context,List<String> listheaders,HashMap<String,List<String>> headerchilds)
    {
        this.con=context;
        this.headers=listheaders;
        this.headeritems=headerchilds;
    }

      // get child of header
    @Override
    public Object getChild(int groupPosition, int childPosition) {
        return this.headeritems.get(this.headers.get(groupPosition)).get(childPosition);
    }

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

    // return the view of child

    @Override
    public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
        final String childname=(String)getChild(groupPosition,childPosition);
        if(convertView==null)
        {
            LayoutInflater inflater=(LayoutInflater)LayoutInflater.from(con);
            convertView=inflater.inflate(R.layout.header_items,null);
        }
        TextView listchild=(TextView)convertView.findViewById(R.id.headeritem);
        listchild.setText(childname);
        return convertView;
    }

     // returns children count of header
    @Override
    public int getChildrenCount(int groupPosition) {
        return this.headeritems.get(headers.get(groupPosition)).size();
    }

    @Override
    public Object getGroup(int groupPosition) {
        return this.headers.get(groupPosition);
    }

    @Override
    public int getGroupCount() {
        return this.headers.size();
    }

    @Override
    public long getGroupId(int groupPosition) {
        return groupPosition;
    }
     
      //returns the view of group
    @Override
    public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
        String headername=(String)getGroup(groupPosition);
        if(convertView==null)
        {
            LayoutInflater inflater=LayoutInflater.from(con);
            convertView=inflater.inflate(R.layout.listview_header,null);
        }
        TextView header=(TextView)convertView.findViewById(R.id.expandheader);
        header.setText(headername);
        return convertView;
    }

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

    @Override
    public boolean hasStableIds() {
        return false;
    }
}

4. After defining with Custom Expandable Listview Adapter now we will create the MainActivity class which contains ExpandableListview

MainActivity.java

package com.coderzpassion.expanlistsample;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ExpandableListAdapter;
import android.widget.ExpandableListView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    // declare the variable needed in activity
    MyExpandableAdapter expandableadapter;
    ExpandableListView expandableListView;
    List<String> headers;
    HashMap<String,List<String>> headeritems;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //get expandable listview
        expandableListView=(ExpandableListView)findViewById(R.id.expandlist);

        //get data to be set to list
        prepareDummyData();

        // get expandable list adapter
        expandableadapter=new MyExpandableAdapter(this,headers,headeritems);

        //set list adapter to list
        expandableListView.setAdapter(expandableadapter);

        //handling the header items click
        expandableListView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
            @Override
            public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
                Toast.makeText(MainActivity.this,headers.get(groupPosition)+"--"+headeritems.get(headers.get(groupPosition)).get(childPosition),Toast.LENGTH_SHORT).show();
                return false;
            }
        });

        //get the expand of headers
        expandableListView.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
            @Override
            public void onGroupExpand(int groupPosition) {
                Toast.makeText(MainActivity.this,headers.get(groupPosition),Toast.LENGTH_SHORT).show();
            }
        });

        //get the collapse of headers
        expandableListView.setOnGroupCollapseListener(new ExpandableListView.OnGroupCollapseListener() {
            @Override
            public void onGroupCollapse(int groupPosition) {
                Toast.makeText(MainActivity.this,headers.get(groupPosition),Toast.LENGTH_SHORT).show();
            }
        });
    }
     // get dummy data to be set to adapter
    public void prepareDummyData()
    {
        headers=new ArrayList<String>();
        headeritems=new HashMap<String,List<String>>();
        //adding headers
        headers.add("Primary");
        headers.add("Senior Secondary");
        headers.add("College");

        //preparing header items data
        List<String> primary=new ArrayList<String>();
        primary.add("first class");
        primary.add("second class");
        primary.add("third class");

        List<String> secondary=new ArrayList<String>();
        secondary.add("eighth class");
        secondary.add("ninth class");
        secondary.add("tenth class");

        List<String> college=new ArrayList<String>();
        college.add("CSE");
        college.add("ECE");
        college.add("IT");
        //contain header and header items
        headeritems.put(headers.get(0), primary);
        headeritems.put(headers.get(1), secondary);
        headeritems.put(headers.get(2),college);

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}