Android: Expandable List View Example

3 May 2013 By Nithya Vasudevan 73,709 views 31 Comments
56 Flares Twitter 2 Facebook 26 Google+ 28 56 Flares ×

Project Description

  • In this example, we will see how to create a simple expandable list view using Android’s ExpandableListView widget. Also we will see how to delete child items in listview
  • Expandable List allows two levels – groups which can individually be expanded to show its children.
  • This example uses custom adapter for ExpandableListView which extends BaseExpandableListAdapter to populate items associated with this view.
  • This expandable list view example explains the following;
    • Each child item has a TextView and ImageView with delete icon.
    • Toast is displayed when a child item is clicked. This is processed in setOnChildClickListener.
    • Child item can be deleted by clicking on delete icon.

Output

Environment Used

Android Project

Create an Android project and name it as ExpandableListDemo.

strings.xml

Open res/values/strings.xml and replace it with following content.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">ExpandableListDemo</string>
    <string name="hello_world">Hello world!</string>
    <string name="menu_settings">Settings</string>
    <string name="title_activity_expandable_list">ExpandableList Demo</string>
</resources>

XML layout files

This Android Expandable List View requires three layout files; one for displaying the main layout containing the ExpandableListView, one for group item layout and other for child item layout.

activity_main.xml

This XML layout file (activity_main.xml) is used for defining ExpandableListView.

Open activity_main.xml file in res/layout and copy the following content.

<RelativeLayout 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"
    tools:context=".MainActivity" >

    <ExpandableListView
        android:id="@+id/laptop_list"
        android:layout_width="match_parent"
        android:layout_height="fill_parent" >
    </ExpandableListView>
    
</RelativeLayout>

group_item.xml

Create a new layout file group_item.xml in res/layout and copy the following content.

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

    <TextView 
        android:id="@+id/laptop"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingLeft="25dp"/>
</LinearLayout>

This group layout contains a TextView to display laptop brand.

child_item.xml

Create a new layout file child_item.xml in res/layout and copy the following content.

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

    <TextView
        android:id="@+id/laptop"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_centerVertical="true"
        android:paddingLeft="25dp" />

    <ImageView
        android:id="@+id/delete"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:src="@drawable/ic_delete" 
        android:contentDescription="@string/app_name"/>

</RelativeLayout>

Each child item contains one TextView to display laptop brand’s model and one ImageView with delete icon to delete a child item.

Create Android Custom Adapter class for ExpandableListView

Create a new Java class “ExpandableListAdapter.java” in package “com.theopentutorials.expandablelist.adapters” and copy the following code.

package com.theopentutorials.expandablelist.adapters;

import java.util.List;
import java.util.Map;

import com.theopentutorials.expandablelist.R;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Typeface;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.ImageView;
import android.widget.TextView;

public class ExpandableListAdapter extends BaseExpandableListAdapter {

	private Activity context;
	private Map<String, List<String>> laptopCollections;
	private List<String> laptops;

	public ExpandableListAdapter(Activity context, List<String> laptops,
			Map<String, List<String>> laptopCollections) {
		this.context = context;
		this.laptopCollections = laptopCollections;
		this.laptops = laptops;
	}

	public Object getChild(int groupPosition, int childPosition) {
		return laptopCollections.get(laptops.get(groupPosition)).get(childPosition);
	}

	public long getChildId(int groupPosition, int childPosition) {
		return childPosition;
	}
	
	
	public View getChildView(final int groupPosition, final int childPosition,
			boolean isLastChild, View convertView, ViewGroup parent) {
		final String laptop = (String) getChild(groupPosition, childPosition);
		LayoutInflater inflater = context.getLayoutInflater();
		
		if (convertView == null) {
			convertView = inflater.inflate(R.layout.child_item, null);
		}
		
		TextView item = (TextView) convertView.findViewById(R.id.laptop);
		
		ImageView delete = (ImageView) convertView.findViewById(R.id.delete);
		delete.setOnClickListener(new OnClickListener() {
			
			public void onClick(View v) {
				AlertDialog.Builder builder = new AlertDialog.Builder(context);
				builder.setMessage("Do you want to remove?");
				builder.setCancelable(false);
				builder.setPositiveButton("Yes",
						new DialogInterface.OnClickListener() {
							public void onClick(DialogInterface dialog, int id) {
								List<String> child = 
									laptopCollections.get(laptops.get(groupPosition));
								child.remove(childPosition);
								notifyDataSetChanged();
							}
						});
				builder.setNegativeButton("No",
						new DialogInterface.OnClickListener() {
							public void onClick(DialogInterface dialog, int id) {
								dialog.cancel();
							}
						});
				AlertDialog alertDialog = builder.create();
				alertDialog.show();
			}
		});
		
		item.setText(laptop);
		return convertView;
	}

	public int getChildrenCount(int groupPosition) {
		return laptopCollections.get(laptops.get(groupPosition)).size();
	}

	public Object getGroup(int groupPosition) {
		return laptops.get(groupPosition);
	}

	public int getGroupCount() {
		return laptops.size();
	}

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

	public View getGroupView(int groupPosition, boolean isExpanded,
			View convertView, ViewGroup parent) {
		String laptopName = (String) getGroup(groupPosition);
		if (convertView == null) {
			LayoutInflater infalInflater = (LayoutInflater) context
					.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
			convertView = infalInflater.inflate(R.layout.group_item,
					null);
		}
		TextView item = (TextView) convertView.findViewById(R.id.laptop);
		item.setTypeface(null, Typeface.BOLD);
		item.setText(laptopName);
		return convertView;
	}

	public boolean hasStableIds() {
		return true;
	}

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

This class uses BaseExpandableListAdapter for creating custom adapter for ExpandableListView.

Activity

Open your activity class and copy the following code.

package com.theopentutorials.expandablelist;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import com.theopentutorials.expandablelist.adapters.ExpandableListAdapter;

import android.app.Activity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.Menu;
import android.view.View;
import android.widget.ExpandableListView;
import android.widget.ExpandableListView.OnChildClickListener;
import android.widget.Toast;

public class MainActivity extends Activity {

	List<String> groupList;
	List<String> childList;
	Map<String, List<String>> laptopCollection;
	ExpandableListView expListView;

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

		createGroupList();

		createCollection();

		expListView = (ExpandableListView) findViewById(R.id.laptop_list);
		final ExpandableListAdapter expListAdapter = new ExpandableListAdapter(
				this, groupList, laptopCollection);
		expListView.setAdapter(expListAdapter);

		//setGroupIndicatorToRight();

		expListView.setOnChildClickListener(new OnChildClickListener() {

			public boolean onChildClick(ExpandableListView parent, View v,
					int groupPosition, int childPosition, long id) {
				final String selected = (String) expListAdapter.getChild(
						groupPosition, childPosition);
				Toast.makeText(getBaseContext(), selected, Toast.LENGTH_LONG)
						.show();

				return true;
			}
		});
	}

	private void createGroupList() {
		groupList = new ArrayList<String>();
		groupList.add("HP");
		groupList.add("Dell");
		groupList.add("Lenovo");
		groupList.add("Sony");
		groupList.add("HCL");
		groupList.add("Samsung");
	}

	private void createCollection() {
		// preparing laptops collection(child)
		String[] hpModels = { "HP Pavilion G6-2014TX", "ProBook HP 4540",
				"HP Envy 4-1025TX" };
		String[] hclModels = { "HCL S2101", "HCL L2102", "HCL V2002" };
		String[] lenovoModels = { "IdeaPad Z Series", "Essential G Series",
				"ThinkPad X Series", "Ideapad Z Series" };
		String[] sonyModels = { "VAIO E Series", "VAIO Z Series",
				"VAIO S Series", "VAIO YB Series" };
		String[] dellModels = { "Inspiron", "Vostro", "XPS" };
		String[] samsungModels = { "NP Series", "Series 5", "SF Series" };

		laptopCollection = new LinkedHashMap<String, List<String>>();

		for (String laptop : groupList) {
			if (laptop.equals("HP")) {
				loadChild(hpModels);
			} else if (laptop.equals("Dell"))
				loadChild(dellModels);
			else if (laptop.equals("Sony"))
				loadChild(sonyModels);
			else if (laptop.equals("HCL"))
				loadChild(hclModels);
			else if (laptop.equals("Samsung"))
				loadChild(samsungModels);
			else
				loadChild(lenovoModels);

			laptopCollection.put(laptop, childList);
		}
	}

	private void loadChild(String[] laptopModels) {
		childList = new ArrayList<String>();
		for (String model : laptopModels)
			childList.add(model);
	}

	private void setGroupIndicatorToRight() {
		/* Get the screen width */
		DisplayMetrics dm = new DisplayMetrics();
		getWindowManager().getDefaultDisplay().getMetrics(dm);
		int width = dm.widthPixels;

		expListView.setIndicatorBounds(width - getDipsFromPixel(35), width
				- getDipsFromPixel(5));
	}

	// Convert pixel to dip
	public int getDipsFromPixel(float pixels) {
		// Get the screen's density scale
		final float scale = getResources().getDisplayMetrics().density;
		// Convert the dps to pixels, based on density scale
		return (int) (pixels * scale + 0.5f);
	}

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

  • Here, we create list of group items stored in ‘groupList’. We create list of child items for each group stored in ‘childList’.
  • We then create a Map where each key is a group name (in this example, it is a laptop brand name) and each value is a list of child (in this example, it is list of laptop models in particular brand).
  • We then create expandable list view adapter and set this adapter in ExpandableListView.
  • In setOnChildClickListener, we display a Toast.
  • By default the group indicator is displayed in left hand side. If you want to display it in right hand side then uncomment “//setGroupIndicatorToRight();” line inside onCreate().
    • We get the width of the screen and use setIndicatorBounds(int left, int right) method to set the indicator bounds for the group view of an expandable list view.

AndroidManifest.xml

Define the activity in AndroidManifest.xml file.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.theopentutorials.expandablelist"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.theopentutorials.expandablelist.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Output

Run your application and you will get the output as shown in the beginning of this tutorial.

If you want to set the group indicator of expandable list to right side then uncomment the highlighted line in onCreate() method. You will get the output as shown below.

Project Folder Structure

The complete folder structure of this example is shown below.

Tags: , , , , , ,

  • titusfx

    You got a little error in your file child_item.xml. You need to change the property src for “@android:drawable/ic_delete”

    • Vishwas Shashidhar

      You need to add an icon for delete…

  • Rob

    Very nice example! Excellent job and very helpful!
    Thank you

  • Nicolas

    Very nice tutorial! I was exactly looking for something like this: an example using the 3 different layouts.

    Good job ;)

  • Peter

    I bow to you! I was struggling with deleting a group for days! Thank you!

  • neto

    Hi, Very nice example, but I have one question … in

    final ExpandableListAdapter expListAdapter ExpandableListAdapter = new (this, groupList, laptopCollection);

    My app say Can not instantiate the type ExpandableListAdapter.

    what can I do?

    • Neto

      everything is correct now was missing just a little detail.

      • hicham1991

        was is missing plzz i have the same problem
        thx

        • Sharjeel

          You need to
          setContentView(your xml) .
          It worked for me.

  • hicham1991

    hello thx for this example ,can you plz tell me how to put an expandablelistview in a drawerlayout so i can slide it ??

    thx again

  • Jimson

    Hi thx for the tutorial. I have the same problem as hicham1991. I would like to put and expandablelistview into a Fragment. I’ve tried everything whithout success.
    thank for your help

  • Bhavesh

    very helpful….
    thanks :)

  • Pingback: Android Expandable List Example | Android Notes

  • Pingback: Expandable List with image on child items | Learn Android Today

  • Mohammed

    Dear,

    Big thanks for this helpful tutorial. I have one proble, where only the parent are shown and when click on the icon to expand, it is not!

  • indrajeet kumar

    Very Helpful tutorial.Thanks a lot…

  • kaushal

    expandable listview layout how to set in tablet in better way? pls help me ASAP pls

  • saber

    salam

  • Alex Dodu

    Thank you Nithya, this page has helped me a lot with the Expandible List View. It has helped me also yet with another problem: I already extended ActionBarActivity, so I couldn’t extend ListView too. Your tutorial has solved also this problem. as you have an ExpandableListView attribute and then apply setAdapter(adapter) on it. Thank you!

  • ella

    hi,

    from some reason the java files don’t identify laptop_list, laptop and delete:

    expListView = (ExpandableListView) findViewById(R.id.laptop_list) in MainActivity,

    if (convertView == null) {
    convertView = inflater.inflate(R.layout.child_item, null);
    }

    TextView item = (TextView) convertView.findViewById(R.id.laptop);

    ImageView delete = (ImageView) convertView.findViewById(R.id.delete);
    in the second file.

    pluss there is an error in the next places (second java file):
    convertView = infalInflater.inflate(R.layout.group_item,
    null);
    }
    TextView item = (TextView) convertView.findViewById(R.id.laptop);

    does anyone know what can it be? it would help me alot

    • Alex Dodu

      Hi ella, I had a similar problem inilially.
      You must have an import of:
      import com.theopentutorials.expandablelist.R; – in the second file, if the two files are in different packages.
      And then make right-click on the project and Refresh to be sure.
      Otherwise it does not see R file.

  • Vinod Rajan

    I would like to pass image url for each sub category thru group children, image url will be different for each how can we do this.

    I passed subcatname like this.

    String subcatname = jsonSubCatNode.optString(“ChildName”).toString();
    group.children.add(subcatname);

    for passing both image url and subcatname how?

  • beni

    how to populate expandable list view using webservice.net can u help my please

  • yosef birhane

    tnxs for all but i have one question , how can we change the list from database not from java file?

  • sandy

    thankyou for your tutorial really helpful

  • Sahbi

    could you please do a tutorial on how to get data from database using Json and then adding that data to this expandable list view ?

  • Pingback: Android: RuntimeException: Unable to start activity ComponentInfoCopyQuery CopyQuery | Question & Answer Tool for your Technical Queries,CopyQuery, ejjuit, query, copyquery, copyquery.com, android doubt, ios question, sql query, sqlite query, nodejsqu

  • Yim

    Could you give me some example of Expandable working with json?

  • http://www.teknowlodgy.com/ Aavishkar

    I am not getting that up and down arrow in expandable list.. how did you do it?

  • adam

    help me please : I have same problem in class ExpandableListAdapter, if I try write this lines

    if (convertView == null) {

    convertView = inflater.inflate(R.layout.child_item, null);

    }
    TextView item = (TextView) convertView.findViewById(R.id.txtvlistitems);

    and

    if (convertView == null) {
    LayoutInflater infalInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

    convertView = infalInflater.inflate(R.layout.group_item, null);
    }

    TextView item = (TextView) convertView.findViewById(R.id.txtvlistprincipal);

    I have error ( (R.layout.child_item,) not find child_item

    error in (R.id.txtvlistitems) -> change…..

    And same with

    I have error ( (R.layout.group_item, null) not find group_item

    error in (R.id.txtvlistprincipal) -> change …

  • http://arturovillela.net Charlie

    Great tutorials, this is the second one i finish from your page.. but i think you should put the code for everyone to download.
    Thnks for taking the time to do and post this. :)