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.
As seen in the Custom ListView we can use a type of array adapter to control the data displayed in the expandable list view. We will use the BaseExpandableListAdapter to supply and control the data displayed in this tutorial.
In this example I will show you how to implement ExpandableListView.
Let’s get start by creating a project in Eclipse IDE.
1. Create a new project in Eclipse by navigating to File ⇒ New Android ⇒ Application Project and fill required details. (I kept my main activity name as MainActivity.java).
2. Create a layout file for MainActivtiy.java under res ⇒ layout folder. I named the layout file as activity_main.xml. In this layout i had taken one expandable listview.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" android:padding="5dp" > <ExpandableListView android:id="@+id/simple_expandable_listview" android:layout_width="fill_parent" android:layout_height="wrap_content" android:divider="#000000" android:dividerHeight="1dp" > </ExpandableListView> </LinearLayout> |
3. For expandablelsitview header items create a new xml file naming header.xml with TextView.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<?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="5dp" > <TextView android:id="@+id/header" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginLeft="5dp" android:textColor="#ff00" android:drawablePadding="10dp" android:textSize="18sp" /> </LinearLayout> |
4. Now, for child items create a new xml file naming childs.xml with TextView.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<?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="5dp" > <TextView android:id="@+id/child" android:padding="10dp" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginLeft="20dp" android:textColor="#000000" android:textSize="13sp" /> </LinearLayout> |
5. Create a new class naming ExpandableListAdapter.java for ExpandableListView adapter as we done in ListView. In this class we set the header and child items fro expandablelistview by inflating both header and child layout.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
package com.android_expandablelistview_demo; 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; //For expandable list view use BaseExpandableListAdapter public class ExpandableListAdapter extends BaseExpandableListAdapter { private Context _context; private List<String> header; // header titles // Child data in format of header title, child title private HashMap<String, List<String>> child; public ExpandableListAdapter(Context context, List<String> listDataHeader, HashMap<String, List<String>> listChildData) { this._context = context; this.header = listDataHeader; this.child = listChildData; } @Override public Object getChild(int groupPosition, int childPosititon) { // This will return the child return this.child.get(this.header.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) { // Getting child text final String childText = (String) getChild(groupPosition, childPosition); // Inflating child layout and setting textview if (convertView == null) { LayoutInflater infalInflater = (LayoutInflater) this._context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = infalInflater.inflate(R.layout.childs, parent, false); } TextView child_text = (TextView) convertView.findViewById(R.id.child); child_text.setText(childText); return convertView; } @Override public int getChildrenCount(int groupPosition) { // return children count return this.child.get(this.header.get(groupPosition)).size(); } @Override public Object getGroup(int groupPosition) { // Get header position return this.header.get(groupPosition); } @Override public int getGroupCount() { // Get header size return this.header.size(); } @Override public long getGroupId(int groupPosition) { return groupPosition; } @Override public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { // Getting header title String headerTitle = (String) getGroup(groupPosition); // Inflating header layout and setting text if (convertView == null) { LayoutInflater infalInflater = (LayoutInflater) this._context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = infalInflater.inflate(R.layout.header, parent, false); } TextView header_text = (TextView) convertView.findViewById(R.id.header); header_text.setText(headerTitle); // If group is expanded then change the text into bold and change the // icon if (isExpanded) { header_text.setTypeface(null, Typeface.BOLD); header_text.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_up, 0); } else { // If group is not expanded then change the text back into normal // and change the icon header_text.setTypeface(null, Typeface.NORMAL); header_text.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_down, 0); } return convertView; } @Override public boolean hasStableIds() { return false; } @Override public boolean isChildSelectable(int groupPosition, int childPosition) { return true; } } |
6. Now, come to MainActivity.java and add the following code. In this class we set the items to adapter and set it to expandablelistview and also we worked on some of its methods list expandgroup, collapsegroup, etc.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
package com.android_expandablelistview_demo; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; import android.view.View; import android.widget.ExpandableListView; import android.widget.ExpandableListView.OnChildClickListener; import android.widget.ExpandableListView.OnGroupClickListener; import android.widget.ExpandableListView.OnGroupExpandListener; import android.widget.Toast; public class MainActivity extends ActionBarActivity { private static ExpandableListView expandableListView; private static ExpandableListAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); expandableListView = (ExpandableListView) findViewById(R.id.simple_expandable_listview); // Setting group indicator null for custom indicator expandableListView.setGroupIndicator(null); setItems(); setListener(); } // Setting headers and childs to expandable listview void setItems() { // Array list for header ArrayList<String> header = new ArrayList<String>(); // Array list for child items List<String> child1 = new ArrayList<String>(); List<String> child2 = new ArrayList<String>(); List<String> child3 = new ArrayList<String>(); List<String> child4 = new ArrayList<String>(); // Hash map for both header and child HashMap<String, List<String>> hashMap = new HashMap<String, List<String>>(); // Adding headers to list for (int i = 1; i < 5; i++) { header.add("Group " + i); } // Adding child data for (int i = 1; i < 5; i++) { child1.add("Group 1 - " + " : Child" + i); } // Adding child data for (int i = 1; i < 5; i++) { child2.add("Group 2 - " + " : Child" + i); } // Adding child data for (int i = 1; i < 6; i++) { child3.add("Group 3 - " + " : Child" + i); } // Adding child data for (int i = 1; i < 7; i++) { child4.add("Group 4 - " + " : Child" + i); } // Adding header and childs to hash map hashMap.put(header.get(0), child1); hashMap.put(header.get(1), child2); hashMap.put(header.get(2), child3); hashMap.put(header.get(3), child4); adapter = new ExpandableListAdapter(MainActivity.this, header, hashMap); // Setting adpater over expandablelistview expandableListView.setAdapter(adapter); } // Setting different listeners to expandablelistview void setListener() { // This listener will show toast on group click expandableListView.setOnGroupClickListener(new OnGroupClickListener() { @Override public boolean onGroupClick(ExpandableListView listview, View view, int group_pos, long id) { Toast.makeText(MainActivity.this, "You clicked : " + adapter.getGroup(group_pos), Toast.LENGTH_SHORT).show(); return false; } }); // This listener will expand one group at one time // You can remove this listener for expanding all groups expandableListView .setOnGroupExpandListener(new OnGroupExpandListener() { // Default position int previousGroup = -1; @Override public void onGroupExpand(int groupPosition) { if (groupPosition != previousGroup) // Collapse the expanded group expandableListView.collapseGroup(previousGroup); previousGroup = groupPosition; } }); // This listener will show toast on child click expandableListView.setOnChildClickListener(new OnChildClickListener() { @Override public boolean onChildClick(ExpandableListView listview, View view, int groupPos, int childPos, long id) { Toast.makeText( MainActivity.this, "You clicked : " + adapter.getChild(groupPos, childPos), Toast.LENGTH_SHORT).show(); return false; } }); } } |
7. Now, run the app and you will get the output as shown in video.
Thanks.
Subscribe to us and get the latest news.
15 Comments
Marco
Wednesday, October 14th, 2015Hi, how do I implement the inflate method for different fragments/layouts when clicking on different child items?
Droid
Thursday, October 15th, 2015Hi, sorry friend but i didn’t get your question properly. Can you explain it more?
Thanks.
madhav
Sunday, August 7th, 2016Hello , can u tell me how can i set empty array for one parent item like no child for it and click on parent show toast for it.
Dr. Droid
Sunday, August 7th, 2016Hi Madhav,
For this just pass empty array for parent for which you want no child. Then on click event of that parent check the children count by using method getChildrenCount, it will return you 1 or 0 not sure for empty child. On this basis you can show Toast for it.
Thanks
ankesh kumar
Thursday, March 16th, 2017tutorial is very helpful . but i want to set the arrow at left side . please help thanks . thank u so much for such a good and great tutorials……..
Dr. Droid
Thursday, March 16th, 2017Hi Ankesh Kumar,
To implement arrow at left side you have to replace 107-118 code lines from ExpandableListAdapter java class with below one:
if (isExpanded) {
header_text.setTypeface(null, Typeface.BOLD);
header_text.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_up, 0,
0, 0);
} else {
// If group is not expanded then change the text back into normal
// and change the icon
header_text.setTypeface(null, Typeface.NORMAL);
header_text.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_down, 0,
0, 0);
}
Thanks
Prabhu
Monday, April 10th, 2017Is it Possible to add Fragments as a child in ExpandableListView ?
Urgent Please Reply!!!!
Dr. Droid
Monday, April 10th, 2017Hi Prabhu,
Unfortunately you cannot use fragment in ListView, GridView, ExpandableListView and RecyclerView. if you want to use fragment layout that you can use by providing layout as we use in ListView for custom row layout.
Thanks
Mrittunjay
Tuesday, January 2nd, 2018Please explain how to filter data with search view in top. only filter method
@Override
public boolean onClose() {
// TODO Auto-generated method stub
VisitListAdapter.filterData(“”);
return false;
}
@Override
public boolean onQueryTextSubmit(String query) {
// TODO Auto-generated method stub
VisitListAdapter.filterData(query);
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
// TODO Auto-generated method stub
VisitListAdapter.filterData(Query);
return false;
}
Dr. Droid
Tuesday, January 2nd, 2018Hi Mrittunjay,
Check this link to implement filter : https://www.androhub.com/android-adding-search-functionality-list/
Thanks
Kajal Mehta
Wednesday, July 4th, 2018Hello
tutorial is very helpful . but i want to set data from the server. please help me
M Awais
Thursday, July 25th, 2019Thanks for Nice tutorial. If i want to add an icon (download icon) with arrow, how can i do that.? kindly suggest any solution. Thank you 🙂
Dr. Droid
Friday, July 26th, 2019Hi M Awais,
If you want to make any UI changes like adding an icon you can go to header.xml or child.xml to make any UI changes to Header Section or Child section respectively.
Thanks
Michael
Sunday, March 6th, 2022Thank you for the tutorial. How can i use expandable listview with viewpager.
I mean, when i click on the first child it would of a fragment layout, i can now swipe from that first child to the last child without go back to the expandable listview.
Not just on the first child, i want to swipe from any child i clicked from the expandable listview.
Thank you.
Dr. Droid
Monday, March 21st, 2022Hi Michael,
I think I get confused what exactly the issue you are facing.
Is it possible to explain it a little bit more or you can mail me and attach some rough/mock-up design for reference.
Thanks