Expandable ListView Example

Expandable ListView

This tutorial shows how to display a HashMap with String and ArrayList<String> as key value pairs, in an ExpandableListView.

Step 1: Create a new project with name ExpandableListView and package name com.myexample.listview. Select File/New/New Project. Fill the forms and click “Finish” button.

Step 2: Open res/layout/xml (or) main.xml and add following code. Here we add an ExpandableListView mainListview1.

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

    <ExpandableListView
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:id="@+id/mainListview1"/>

</LinearLayout>

Step 4: In res/layout/ directory add a new file header_item.xml and add following code. Here we add a TextView for displaying the headers of lists.

 <?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="wrap_content"
	android:orientation="horizontal"
	android:background="#990048">

	<TextView
		android:layout_height="wrap_content"
		android:layout_width="match_parent"
		android:text="Large Text"
		android:id="@+id/listitemTextView1"
		android:padding="8dp"
		android:textSize="16sp"
		android:textColor="#FCFCFC"
		android:textStyle="bold"/>

</LinearLayout>

Step 4: In res/layout/ directory add another file child_item.xml and add following code. Here we add a TextView for displaying the children in each list.

 <?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="wrap_content"
	android:orientation="vertical"
	android:padding="10dp">

	<TextView
		android:layout_height="wrap_content"
		android:textAppearance="?android:attr/textAppearanceMedium"
		android:layout_width="match_parent"
		android:text="Medium Text"
		android:textColor="#C00B00"
		android:id="@+id/childitemTextView1"/>

</LinearLayout>

Step 5: Open app/src/main/java/package and open MainActivity.java. Add following code in it.

package com.myexample.listview;

import android.app.*;
import android.os.*;
import android.view.*;
import android.view.View.*;
import android.widget.*;
import java.util.*;
import android.content.*;

public class MainActivity extends Activity {

	private ExpandableListView listview1;
	// Create a HashMap for all groups and their items
	private HashMap<String, ArrayList<String>> allGroups = new HashMap<>();
	// Create a list for all group headings
	ArrayList<String> allheadings;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		
		listview1 = (ExpandableListView) findViewById(R.id.mainListview1);
		
		// Toast item title when ListView item is clicked
		listview1.setOnChildClickListener(new ExpandableListView.OnChildClickListener(){
			@Override
			public boolean onChildClick(ExpandableListView listview, View child, int groupposition, int childposition, long position){
				Toast.makeText(getApplicationContext(), allGroups.get(allheadings.get(groupposition)).get(childposition), Toast.LENGTH_LONG).show();
				return true;
			}
		});
		
		// Create a separate list for each group, and add items to them
		ArrayList<String> group1items = new ArrayList<>();
		group1items.add("Group 1 item 1");
		group1items.add("Group 1 item 2");
		group1items.add("Group 1 item 3");
		group1items.add("Group 1 item 4");
		group1items.add("Group 1 item 5");
		ArrayList<String> group2items = new ArrayList<>();
		group2items.add("Group 2 item 1");
		group2items.add("Group 2 item 2");
		group2items.add("Group 2 item 3");
		group2items.add("Group 2 item 4");
		ArrayList<String> group3items = new ArrayList<>();
		group3items.add("Group 3 item 1");
		group3items.add("Group 3 item 2");
		group3items.add("Group 3 item 3");
		group3items.add("Group 3 item 4");
		group3items.add("Group 3 item 5");
		ArrayList<String> group4items = new ArrayList<>();
		group4items.add("Group 4 item 1");
		group4items.add("Group 4 item 2");
		group4items.add("Group 4 item 3");
		
		// put the lists created above in the HashMap allGroups, with separate keys
		allGroups.put("This is Group 1", group1items);
		allGroups.put("This is Group 2", group2items);
		allGroups.put("This is Group 3", group3items);
		allGroups.put("This is Group 4", group4items);
		
		// Add all keys in HashMap allGroups to List String allheadings
		allheadings = new ArrayList<String>(allGroups.keySet());
		
		// Create a new CustomListAdapter and set it as adapter of ExpandableListView
		CustomListAdapter adapter = new CustomListAdapter(this, allGroups, allheadings);
		listview1.setAdapter(adapter);
		((BaseAdapter)listview1.getAdapter()).notifyDataSetChanged();
		
	}
	
	public class CustomListAdapter extends BaseExpandableListAdapter {
		private Context context;
		HashMap<String, ArrayList<String>> groups;
		ArrayList<String> headings;
		
		// Public constructor 
		public CustomListAdapter(Context context, HashMap<String, ArrayList<String>> groups, ArrayList<String> headings) {
			this.context = context;
			this.groups = groups;
			this.headings = headings;
		}

		@Override
		public int getGroupCount() {
			// Return total number of groups
			return headings.size();
		}
		
		@Override
		public int getChildrenCount(int position) {
			// Return total items in each group
			return groups.get(headings.get(position)).size();
		}

		@Override
		public Object getGroup(int position) {
			// Return group heading
			return headings.get(position);
		}
		
		@Override
		public Object getChild(int groupposition, int childposition) {
			// Return child from specified group at the specified position
			return groups.get(headings.get(groupposition)).get(childposition);
		}

		@Override
		public long getGroupId(int position) {
			return position;
		}
		
		@Override
		public long getChildId(int groupposition, int childposition) {
			return childposition;
		}
		
		@Override
		public boolean hasStableIds() {
			return false;
		}

		@Override
		public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent){
			View v = convertView;
			// Inflate the layout for each list row
			LayoutInflater _inflater = (LayoutInflater)getBaseContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
			if (v == null) {
				v = _inflater.inflate(R.layout.header_item, null);
			}
			// Set Width of ListView to MATCH_PARENT
			parent.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
			// Get the TextView from CustomView for displaying group headings
			TextView txtview = (TextView) v.findViewById(R.id.listitemTextView1);
			// Set the text and image for current item using data from map list
            txtview.setText(headings.get(groupPosition));
			// Return the view for the current row
			return v;
		}
		
		@Override
		public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent){
			View v = convertView;
			// Inflate the layout for each list row
			LayoutInflater _inflater = (LayoutInflater)getBaseContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
			if (v == null) {
				v = _inflater.inflate(R.layout.child_item, null);
			}
			// Set Width of ListView to MATCH_PARENT
			parent.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
			// Get the TextView from CustomView for displaying children
			TextView txtview = (TextView) v.findViewById(R.id.childitemTextView1);
			// Set the text for current item using data from map list
			txtview.setText((groups.get(headings.get(groupPosition))).get(childPosition));
			// Return the view for the current row
			return v;
		}

		@Override
		public boolean isChildSelectable(int groupposition, int childposition)
		{
			return true;
		}

	}
	
}

Output:
Now run the app. The app will display a ExpandableListView.