Expandable list view is used to group list data by categories. It has the capability of expanding and collapsing the groups when user touches header.
If you are not aware of list view before please refer to this tutorial Android ListView Tutorial
Let’s start by creating a new project..
1. Create a new project in the Eclipse IDE from File ⇒ Android Application Project and fill all required details. I left my main activity name as MainActivity.java
2. In order to create an expandable list view, we need three xml layout files. First one is for main listview, 2nd one for list view group item and 3rd one is for list view child item. Open your activity_main.xml and add ExpandableListView element.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" android:background="#f4f4f4" > <ExpandableListView android:id="@+id/lvExp" android:layout_height="match_parent" android:layout_width="match_parent"/> </LinearLayout>
3. Create another xml layout for list view group header. I created an xml file named list_group.xml and pasted following code.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="8dp" android:background="#000000"> <TextView android:id="@+id/lblListHeader" android:layout_width="fill_parent" android:layout_height="wrap_content" android:paddingLeft="?android:attr/expandableListPreferredItemPaddingLeft" android:textSize="17dp" android:textColor="#f9f93d" /> </LinearLayout>
4.Create one more xml file named list_item.xml for child list item. This will contain simple TextView element.
<?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="55dip" android:orientation="vertical" > <TextView android:id="@+id/lblListItem" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textSize="17dip" android:paddingTop="5dp" android:paddingBottom="5dp" android:paddingLeft="?android:attr/expandableListPreferredChildPaddingLeft" /> </LinearLayout>
5. I am using a custom adapter class to create list view. Create a new class file called ExpandableListAdapter.java and extend this from BaseExpandableListAdapter. This class provides required methods to render listview.
getGroupView() – Returns view for the list group header
getChildView() – Returns view for list child item
package info.androidhive.expandablelistview; import java.util.HashMap; import java.util.List; import android.content.Context; import android.graphics.Typeface; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseExpandableListAdapter; import android.widget.TextView; public class ExpandableListAdapter extends BaseExpandableListAdapter { private Context _context; private List<String> _listDataHeader; // header titles // child data in format of header title, child title private HashMap<String, List<String>> _listDataChild; public ExpandableListAdapter(Context context, List<String> listDataHeader, HashMap<String, List<String>> listChildData) { this._context = context; this._listDataHeader = listDataHeader; this._listDataChild = listChildData; } @Override public Object getChild(int groupPosition, int childPosititon) { return this._listDataChild.get(this._listDataHeader.get(groupPosition)) .get(childPosititon); } @Override public long getChildId(int groupPosition, int childPosition) { return childPosition; } @Override public View getChildView(int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { final String childText = (String) getChild(groupPosition, childPosition); if (convertView == null) { LayoutInflater infalInflater = (LayoutInflater) this._context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = infalInflater.inflate(R.layout.list_item, null); } TextView txtListChild = (TextView) convertView .findViewById(R.id.lblListItem); txtListChild.setText(childText); return convertView; } @Override public int getChildrenCount(int groupPosition) { return this._listDataChild.get(this._listDataHeader.get(groupPosition)) .size(); } @Override public Object getGroup(int groupPosition) { return this._listDataHeader.get(groupPosition); } @Override public int getGroupCount() { return this._listDataHeader.size(); } @Override public long getGroupId(int groupPosition) { return groupPosition; } @Override public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { String headerTitle = (String) getGroup(groupPosition); if (convertView == null) { LayoutInflater infalInflater = (LayoutInflater) this._context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = infalInflater.inflate(R.layout.list_group, null); } TextView lblListHeader = (TextView) convertView .findViewById(R.id.lblListHeader); lblListHeader.setTypeface(null, Typeface.BOLD); lblListHeader.setText(headerTitle); return convertView; } @Override public boolean hasStableIds() { return false; } @Override public boolean isChildSelectable(int groupPosition, int childPosition) { return true; } }
6. Once you are done with customer adapter, open your MainActivity.java and do the following changes. In the following I created required data needed for list view and passed it to custom adapter.
package info.androidhive.expandablelistview; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.ExpandableListView; import android.widget.ExpandableListView.OnChildClickListener; import android.widget.ExpandableListView.OnGroupClickListener; import android.widget.ExpandableListView.OnGroupCollapseListener; import android.widget.ExpandableListView.OnGroupExpandListener; import android.widget.Toast; public class MainActivity extends Activity { ExpandableListAdapter listAdapter; ExpandableListView expListView; List<String> listDataHeader; HashMap<String, List<String>> listDataChild; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // get the listview expListView = (ExpandableListView) findViewById(R.id.lvExp); // preparing list data prepareListData(); listAdapter = new ExpandableListAdapter(this, listDataHeader, listDataChild); // setting list adapter expListView.setAdapter(listAdapter); } /* * Preparing the list data */ private void prepareListData() { listDataHeader = new ArrayList<String>(); listDataChild = new HashMap<String, List<String>>(); // Adding child data listDataHeader.add("Top 250"); listDataHeader.add("Now Showing"); listDataHeader.add("Coming Soon.."); // Adding child data List<String> top250 = new ArrayList<String>(); top250.add("The Shawshank Redemption"); top250.add("The Godfather"); top250.add("The Godfather: Part II"); top250.add("Pulp Fiction"); top250.add("The Good, the Bad and the Ugly"); top250.add("The Dark Knight"); top250.add("12 Angry Men"); List<String> nowShowing = new ArrayList<String>(); nowShowing.add("The Conjuring"); nowShowing.add("Despicable Me 2"); nowShowing.add("Turbo"); nowShowing.add("Grown Ups 2"); nowShowing.add("Red 2"); nowShowing.add("The Wolverine"); List<String> comingSoon = new ArrayList<String>(); comingSoon.add("2 Guns"); comingSoon.add("The Smurfs 2"); comingSoon.add("The Spectacular Now"); comingSoon.add("The Canyons"); comingSoon.add("Europa Report"); listDataChild.put(listDataHeader.get(0), top250); // Header, Child data listDataChild.put(listDataHeader.get(1), nowShowing); listDataChild.put(listDataHeader.get(2), comingSoon); } }
Run your project, you should see following output. (Note: The list view group indicators might change depending upon your android version)
ListView child item click listener
Detecting the child item click can be done by implementing setOnChildClickListener listener on listview.
// Listview on child click listener expListView.setOnChildClickListener(new OnChildClickListener() { @Override public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) { Toast.makeText( getApplicationContext(), listDataHeader.get(groupPosition) + " : " + listDataChild.get( listDataHeader.get(groupPosition)).get( childPosition), Toast.LENGTH_SHORT) .show(); return false; } });
Listening when group is expanded
You may want to execute some lines of code when the listview group is expanded. For this you can use setOnGroupExpandListener which triggers an event when listview group expanded.
// Listview Group expanded listener expListView.setOnGroupExpandListener(new OnGroupExpandListener() { @Override public void onGroupExpand(int groupPosition) { Toast.makeText(getApplicationContext(), listDataHeader.get(groupPosition) + " Expanded", Toast.LENGTH_SHORT).show(); } });
Listening when group is collapsed
Implementing setOnGroupCollapseListener will trigger an event when listview group is collapsed.
// Listview Group collasped listener expListView.setOnGroupCollapseListener(new OnGroupCollapseListener() { @Override public void onGroupCollapse(int groupPosition) { Toast.makeText(getApplicationContext(), listDataHeader.get(groupPosition) + " Collapsed", Toast.LENGTH_SHORT).show(); } });
Complete Code
Here is the final code for MainActivity.java
package info.androidhive.expandablelistview; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.ExpandableListView; import android.widget.ExpandableListView.OnChildClickListener; import android.widget.ExpandableListView.OnGroupClickListener; import android.widget.ExpandableListView.OnGroupCollapseListener; import android.widget.ExpandableListView.OnGroupExpandListener; import android.widget.Toast; public class MainActivity extends Activity { ExpandableListAdapter listAdapter; ExpandableListView expListView; List<String> listDataHeader; HashMap<String, List<String>> listDataChild; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // get the listview expListView = (ExpandableListView) findViewById(R.id.lvExp); // preparing list data prepareListData(); listAdapter = new ExpandableListAdapter(this, listDataHeader, listDataChild); // setting list adapter expListView.setAdapter(listAdapter); // Listview Group click listener expListView.setOnGroupClickListener(new OnGroupClickListener() { @Override public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) { // Toast.makeText(getApplicationContext(), // "Group Clicked " + listDataHeader.get(groupPosition), // Toast.LENGTH_SHORT).show(); return false; } }); // Listview Group expanded listener expListView.setOnGroupExpandListener(new OnGroupExpandListener() { @Override public void onGroupExpand(int groupPosition) { Toast.makeText(getApplicationContext(), listDataHeader.get(groupPosition) + " Expanded", Toast.LENGTH_SHORT).show(); } }); // Listview Group collasped listener expListView.setOnGroupCollapseListener(new OnGroupCollapseListener() { @Override public void onGroupCollapse(int groupPosition) { Toast.makeText(getApplicationContext(), listDataHeader.get(groupPosition) + " Collapsed", Toast.LENGTH_SHORT).show(); } }); // Listview on child click listener expListView.setOnChildClickListener(new OnChildClickListener() { @Override public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) { // TODO Auto-generated method stub Toast.makeText( getApplicationContext(), listDataHeader.get(groupPosition) + " : " + listDataChild.get( listDataHeader.get(groupPosition)).get( childPosition), Toast.LENGTH_SHORT) .show(); return false; } }); } /* * Preparing the list data */ private void prepareListData() { listDataHeader = new ArrayList<String>(); listDataChild = new HashMap<String, List<String>>(); // Adding child data listDataHeader.add("Top 250"); listDataHeader.add("Now Showing"); listDataHeader.add("Coming Soon.."); // Adding child data List<String> top250 = new ArrayList<String>(); top250.add("The Shawshank Redemption"); top250.add("The Godfather"); top250.add("The Godfather: Part II"); top250.add("Pulp Fiction"); top250.add("The Good, the Bad and the Ugly"); top250.add("The Dark Knight"); top250.add("12 Angry Men"); List<String> nowShowing = new ArrayList<String>(); nowShowing.add("The Conjuring"); nowShowing.add("Despicable Me 2"); nowShowing.add("Turbo"); nowShowing.add("Grown Ups 2"); nowShowing.add("Red 2"); nowShowing.add("The Wolverine"); List<String> comingSoon = new ArrayList<String>(); comingSoon.add("2 Guns"); comingSoon.add("The Smurfs 2"); comingSoon.add("The Spectacular Now"); comingSoon.add("The Canyons"); comingSoon.add("Europa Report"); listDataChild.put(listDataHeader.get(0), top250); // Header, Child data listDataChild.put(listDataHeader.get(1), nowShowing); listDataChild.put(listDataHeader.get(2), comingSoon); } }
Hi there! I am Founder at androidhive and programming enthusiast. My skills includes Android, iOS, PHP, Ruby on Rails and lot more. If you have any idea that you would want me to develop? Let’s talk: ravi@androidhive.info
first comment , thank you
Third comment ….. you are welcome 🙂
forever comment @Ravi Tamada:disqus is great great great …
🙂
HI Ravi..i understood this example..How can i add Edittext an Button in childview?
You can add them in list_item.xml file
yes but..when in the adapter i set the listener it wont listen!!! you know why?
Ravi… excellent work… Anyone can make great apps relying on codes presented here. Through people like you we will be increasing the overall quality of android apps. I particularly have a easier learning when altering ready codes and making changes to see the behavior .. Congratulations…. I will click all the sponsors that I can.
Thank you Filipe for your support 🙂
Hi ravi u r doing a great job. Its very helpful for every one start doing their apps.
Try to update daily one concept even it is small also no problem.It will also be helpful for someone..Keep doing.
Thanks,But how to anmiate expand and collapse?
Any way to animate expanding the list items?
Excellent explanation, thanks 😉
Thank you for the tutorail, God bless you
Parfait :))))
As good as always, well done.
Hey can u add the code to “auto close the all previous opened list and only opens the currently expandable list “??
expListView.setAdapter(listAdapter);
expListView.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
int previousGroup = -1;
@Override
public void onGroupExpand(int groupPosition) {
if(groupPosition != previousGroup)
expListView.collapseGroup(previousGroup);
previousGroup = groupPosition;
}
});
wow.. wow wow.. what an excellent tutorial..
Great Work Ravi this is really helpful thanks 🙂
Hi, your tutorial is great!
but when I run the project it doesn’t show the indicators.
If I try to click the header this action generate the following error:
Unexpected error while launching logcat. Try reselecting the device.] device not found
com.android.ddmlib.AdbCommandRejectedException: device not found
at com.android.ddmlib.AdbHelper.setDevice(AdbHelper.java:752)
at com.android.ddmlib.AdbHelper.executeRemoteCommand(AdbHelper.java:373)
at com.android.ddmlib.Device.executeShellCommand(Device.java:462)
at com.android.ddmuilib.logcat.LogCatReceiver$1.run(LogCatReceiver.java:109)
at java.lang.Thread.run(Thread.java:724)
any help?
Thanks
Seems like your device is not detected by your Operating system,try to install appropriate device drivers first
Sir ! i wana get record from data base ,how can i?
how to start new activity in child data using expandablelist.?
Dear Ravi,
My name is Beatriz Hernández and I get in touch
with you because we are developing an advertising campaign which we would like
to count on you.
If you are interested , please write me
back and I will tell you more about the project.
Best regards,
Beatriz
Hi Beatriz,
Sorry for the delayed reply. Please mail me the details to ravi8x@gmail.com
Thank you
Hey Ravi
I want to add an element in expandable list
as we do in listview by using adapter.addall(arraylist)
how to perform this in Expandable list view
thank you!
awesome awesome awesome……………………
Thank You 🙂
Excellent tutorial! Is just what I was looking for, I want to modify a bit your listview, I pretend to put some buttons in the listview or set an onclick event, Could you help me with that? I need to develop a menu for a restaurant and it’s necessary for me that the program counts the clicks on each product. I hope you can help me with this task .
Hey Ravi good tutorial i want to know how to create ExpandableListView with image and text else a coustom ExpandableListView
Thank You
how to set onClickListener(intent) for any particular child option
nice tutorial..please keep it up…
Hi!
First, thank you for a very great tutorial. As a beginner in Android, you have been a great help to me.
I am currently trying to make your program into a dynamic expandable listview with data coming from a remote server accessed through PHP and JSON (using your other tutorial as reference). However, I’m having problems trying to save the data on the listDataHeader and listDataChild. Could you please share some tips on how to resolve it?
Thanks again and more power!
hi, what if I there is a add button? do you have source code for this? thanks a lot! 🙂
hi nice blog spot , how to implent Expandable List view up to Four levels
Fantastic dude! Im going to attempt to use this with the Navigation drawer. Hopefully it shouldn’t be too bad.
Ravi => Android Sensei !!!
1st thing: great work, thank you so much!
2nd thing: i tried to put a 2nd textview into my childrow.xml but it doesn’t work. i think i’ve made a mistake in the getChildView or in prepareListData… can you (or maybe anybody else) please help me?
would be great!
thank you
“No Empty Constructor” ???
Hi..how do i apply this on a fragment?? where do i put it?on the onCreate or onActivityCreated?
Awesome tutorial..:)..This really helps a lot.
How can I implements this when using fragments? Help would be really appreciated..:)
Very useful article but there is one problem in each article. Problem is that the width of code box is very less so we have to scroll horizontally again and again. so please make it wider if possible
What is your screen resolution?
The best tutorial !!
When i scroll the list item i have a white background. To fix it add the following attribute android:cacheColorHint=”#00000000″ in the xml file : activity_main.xml in ExpandableListView view
Thanks for the tip
How can you add a third level to this? All of the other examples use a completely different form.. this is the best one, but need to add a 3rd level
hardcoded values into expandablelistview. I want to know how do you get generic database values into it?
I stuck badly in my code to implement ExpandableListView and your code can help me A LOT,but when I try your code it gives me an error in this part:
// preparing list data
prepareListData();
listAdapter = new ExpandableListAdapter(this, listDataHeader, listDataChild);
which the error is “Cannot instantiate the type ExpandableListAdapter”
could you please help me to solve it?
Thanks a lot
same error i’m also getting now.
Yes, same error i’m also getting now. But, I don’t find it 🙁
Hey, I find it 🙂 you make a class by “ExpandableListAdapter” name.
This class is adapter class 🙂
Change the class name
“ExpandableListAdapter” to some other. Android have interface class in this name…
Hi, The best tutorial.
I like your tutorials.
I’ve a small doubt, you actually used same image for all list items. But, how to add diff images for list items.
And one more is , can you implement some non expandable list items and some expandable list items like this
http://i.stack.imgur.com/vilHb.png
Thanks,
Siva
Hi Sasa,
I also get the same error, but finally solved.
Just change that a line as
listAdapter = new packageName.ExpandableListAdapter(this, listDataHeader, listDataChild);
instead of listAdapter = new ExpandableListAdapter(this, listDataHeader, listDataChild);
Thanks,
Siva
Hi,
Nice tutorial thankyou but how do i add a second textview to the childview.I mean adding it is easy (you just have to edit the XML) but i don’t understand how to set the adapter to make text appaer in the second textview.
I want a second childview too and a textview in every group please…
Hey nice tutorial, can you tell me how to add empty views as children of every listview element. So that when i click on an item which does not have children, the application does not crash.
Thank a lot for this codes, works perfectly, it was soooo helpful for me, I was desperately looking for codes, thanks again. 🙂
Thanks a lot.
Thanks for this super helpful tutorial!! For those asking about putting in a fragment, I managed to get that working, so thought I would share: (1) fragment extends ListFragment, (2) create a new layout for the fragment with same code as described above for activity_main.xml except change to “android:id=@android:id/list” and inflate this layout in onCreateView in the fragment (3) put this in onActivityCreated:
expListView = (ExpandableListView) getListView();
prepareListData();
adapter = new ExpandableListAdapter(getActivity(), listDataHeader, listDataChild);
expListView.setAdapter(adapter);
Thanks so much, you are a lifesaver!
I dont understand what number 3 is, where is it being added exactly? in OnCreate of the Activity that the frag is being created from?
How can i take off the arrow on the left (the one that indicates if the list is expanded or not ) .. i created my own arrow on the right that’s why i wanna take off the one on the left !!
is it possible to collapse items other than the clicked one
Do you want to expand and collapse all the items at once ?
nope to collapse other groups when a group is clicked. ie expand the clicked and collapse the others.
Hello Shubham,
Try this code. It worked for me.
private int lastExpandedPosition = -1;
private ExpandableListView lv; //your expandable listview
…
lv.setOnGroupExpandListener(new OnGroupExpandListener() {
@Override
public void onGroupExpand(int groupPosition) {
if (lastExpandedPosition != -1
&& groupPosition != lastExpandedPosition) {
lv.collapseGroup(lastExpandedPosition);
}
lastExpandedPosition = groupPosition;
}
});
thanks mate it worked well
Your welcome buddy…
But there is one problem when changing the orientation.
Follow this step to reproduce it :
keep one tab expanded. Now change the orientation of your phone.
Now try to expand another tab. So it won’t collapse the previously selected tab and. So at a time 2 tabs will be expanded….lol
@Ravi Tamada:disqus : How can i implement Search filter Functionality to Expandable listview. ?
Hi Rishil,
Do you implement filter ?
Guys, i have a problem on lines
drawerListView = (ExpandableListView) findViewById(R.id.left_drawer);
listAdapter = ExpandableListAdapter(MainActivity.this, listDataHeader, listDataChild);
drawerListView.setAdapter(listAdapter);
error is “The method setAdapter(ListAdapter) in the type ListView is not applicable for the arguments (ExpandableListAdapter)”. What i’m doing wrong?
“New” is missing after “listAdapter =”
Ok so after taking a good look on this one I was wondering if we could integrate this project on the Drawer navigation. Like for example; we have five default items on the drawer navigation and below that are set of expandable items. Hey Ravi is that possible to integrate this in a Drawer Navigation? I mean both of them are list views right?
Awesome article !
Many thanks !