SimpleExpandableListAdapter in Android with Example

Android ExpandableListView is a view that is used to shows items as a vertically scrolling two-level list. The basic difference with ListView is it allows two levels of the display which are groups that can be easily expanded and collapsed by touching to view and their respective children’s items. In order to show the view, ExpandableListViewAdapter is used in android. In many apps, an ExpandableListView facility is required. For example:

  • In a “city” app(for any city), if the user wants to see a list of engineering colleges/list of art colleges/list of medical colleges, etc.,
  • List of vegetables/List of fruits/List of Nuts etc., for a “jiomart” kind of app
  • List of Hatchback/List of crosscut/List of Sedan etc., for a “Uber” kind of app

Important Methods

Methods

Description

setChildIndicator(Drawable)

Current state indicator for  each item If the child is 

the last child for a group, the state state_last will be set



setGroupIndicator(Drawable)

To represent the state either expanded or collapsed.state_expanded is the

state if the group is expanded, state_collapsed if the state of the group 

is collapsed, state_empty if there are no groups.

getGroupView() Used to get  the view for the list group header
getChildView() Used to get the view for list child item

The Notable Interfaces

Interfaces

Description

ExpandableListView.OnChildClickListener When a child in the expanded list is clicked, this is overridden
ExpandableListView.OnGroupClickListener When a group header in the expanded list is clicked, this is overridden
ExpandableListView.OnGroupCollapseListener When a group is collapsed, this method notifies
ExpandableListView.OnGroupExpandListener When a group is expanded, this method notifies

Example

Let us see the ways to implement SimpleExpandableListAdapter in Android with a List of vegetables/List of fruits/List of Nuts in the ExpandableListAdapter. A sample GIF is given below to get an idea about what we are going to do in this article. Note that we are going to implement this project using the Java language. 

SimpleExpandableListAdapter

Step 1: Create a New Project



To create a new project in Android Studio please refer to How to Create/Start a New Project in Android Studio. Note that select Java as the programming language.

Step 2: Create the dimens.xml file

Go to app > res > values > right-click > New > Values Resource File and name the file as dimens. In this file dimension related information is given here. Below is the code for the dimens.xml file.

XML

filter_none

edit
close

play_arrow

link
brightness_4
code

<resources>
    <!-- Default screen margins, per the Android Design guidelines. -->
    <dimen name="activity_horizontal_margin">16dp</dimen>
    <dimen name="activity_vertical_margin">16dp</dimen>
</resources>

chevron_right


Step 3: Working with the XML files

  • To design the UI, code is present under the res\layout folder in the form of XML. They are used in the Activity files and once the XML file is in scope inside the activity, one can access the components present in the XML. Below is the code for the activity_main.xml file. Comments are added inside the code to understand the code in more detail.

XML

filter_none

edit
close

play_arrow

link
brightness_4
code

<!-- RelativeLayout places the components vertically one by one.
     Necessary parameters also specified so that elegant output can be seen -->
<RelativeLayout 
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context=".MainActivity">
  
    <!-- ExpandableListView is used in relativelayout
         The android:indicatorLeft is the left bound for an items indicator.-->
    <ExpandableListView
        android:id="@+id/expandableListViewSample"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:divider="@android:color/darker_gray"
        android:dividerHeight="0.5dp"
        android:indicatorLeft="?android:attr/expandableListPreferredItemIndicatorLeft" />
  
</RelativeLayout>
<!-- Note: We cannot use the value wrap_content for the android:layout_height
     attribute of the ExpandableListView in XML. -->

chevron_right


  • Go to app > res > layout > New > Layout Resource File and name the file as list_group. Below is the code for the list_group.xml file.

XML

filter_none

edit
close

play_arrow

link
brightness_4
code

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
  
    <TextView
        android:id="@+id/listTitle"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:paddingLeft="?android:attr/expandableListPreferredItemPaddingLeft"
        android:paddingTop="10dp"
        android:paddingBottom="10dp"
        android:textColor="@android:color/black" />
      
</LinearLayout>

chevron_right


  • Next is for layout row for child items. This is done via a list_item.xml file. Go to app > res > layout > New > Layout Resource File and name the file as list_item. Below is the code for the list_item.xml file.

XML

filter_none

edit
close

play_arrow

link
brightness_4
code

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">
  
    <TextView
        android:id="@+id/expandedListItem"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:paddingLeft="?android:attr/expandableListPreferredChildPaddingLeft"
        android:paddingTop="10dp"
        android:paddingBottom="10dp" />
      
</LinearLayout>

chevron_right


  • With the above XML, UI design elements are complete. Next is, a java file to populate the contents of the list.

Step 4: Working with the Java files

  • Go to app > java > your package name > Right-click > New > Java Class and name the file as ExpandableListDataItems. Below is the code for the ExpandableListDataItems.java file. Comments are added inside the code to understand the code in more detail.

Java

filter_none

edit
close

play_arrow

link
brightness_4
code

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
  
public class ExpandableListDataItems {
    public static HashMap<String, List<String>> getData() {
        HashMap<String, List<String>> expandableDetailList = new HashMap<String, List<String>>();
  
        // As we are populating List of fruits, vegetables and nuts, using them here
        // We can modify them as per our choice.
        // And also choice of fruits/vegetables/nuts can be changed
        List<String> fruits = new ArrayList<String>();
        fruits.add("Apple");
        fruits.add("Orange");
        fruits.add("Guava");
        fruits.add("Papaya");
        fruits.add("Pineapple");
  
        List<String> vegetables = new ArrayList<String>();
        vegetables.add("Tomato");
        vegetables.add("Potato");
        vegetables.add("Carrot");
        vegetables.add("Cabbage");
        vegetables.add("Cauliflower");
  
        List<String> nuts = new ArrayList<String>();
        nuts.add("Cashews");
        nuts.add("Badam");
        nuts.add("Pista");
        nuts.add("Raisin");
        nuts.add("Walnut");
  
        // Fruits are grouped under Fruits Items. Similarly the rest two are under
        // Vegetable Items and Nuts Items respecitively.
        // i.e. expandableDetailList object is used to map the group header strings to
        // their respective children using an ArrayList of Strings.
        expandableDetailList.put("Fruits Items", fruits);
        expandableDetailList.put("Vegetable Items", vegetables);
        expandableDetailList.put("Nuts Items", nuts);
        return expandableDetailList;
    }
}

chevron_right


  • Go to app > java > your package name > Right-click > New > Java Class and name the file as CustomizedExpandableListAdapter. Below is the code for the CustomizedExpandableListAdapter.java file. This java class extends BaseExpandableListAdapter and it overrides the methods which are required for the ExpandableListView. Comments are added inside the code to understand the code in more detail.

Java

filter_none

edit
close

play_arrow

link
brightness_4
code

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;
import java.util.HashMap;
import java.util.List;
  
public class CustomizedExpandableListAdapter extends BaseExpandableListAdapter {
  
    private Context context;
    private List<String> expandableTitleList;
    private HashMap<String, List<String>> expandableDetailList;
  
    // constructor
    public CustomizedExpandableListAdapter(Context context, List<String> expandableListTitle,
                                           HashMap<String, List<String>> expandableListDetail) {
        this.context = context;
        this.expandableTitleList = expandableListTitle;
        this.expandableDetailList = expandableListDetail;
    }
  
    @Override
    // Gets the data associated with the given child within the given group.
    public Object getChild(int lstPosn, int expanded_ListPosition) {
        return this.expandableDetailList.get(this.expandableTitleList.get(lstPosn)).get(expanded_ListPosition);
    }
  
    @Override
    // Gets the ID for the given child within the given group.
    // This ID must be unique across all children within the group. Hence we can pick the child uniquely
    public long getChildId(int listPosition, int expanded_ListPosition) {
        return expanded_ListPosition;
    }
  
    @Override
    // Gets a View that displays the data for the given child within the given group.
    public View getChildView(int lstPosn, final int expanded_ListPosition, 
                             boolean isLastChild, View convertView, ViewGroup parent) {
        final String expandedListText = (String) getChild(lstPosn, expanded_ListPosition);
        if (convertView == null) {
            LayoutInflater layoutInflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = layoutInflater.inflate(R.layout.list_item, null);
        }
        TextView expandedListTextView = (TextView) convertView.findViewById(R.id.expandedListItem);
        expandedListTextView.setText(expandedListText);
        return convertView;
    }
  
    @Override
    // Gets the number of children in a specified group.
    public int getChildrenCount(int listPosition) {
        return this.expandableDetailList.get(this.expandableTitleList.get(listPosition)).size();
    }
  
    @Override
    // Gets the data associated with the given group.
    public Object getGroup(int listPosition) {
        return this.expandableTitleList.get(listPosition);
    }
  
    @Override
    // Gets the number of groups.
    public int getGroupCount() {
        return this.expandableTitleList.size();
    }
  
    @Override
    // Gets the ID for the group at the given position. This group ID must be unique across groups.
    public long getGroupId(int listPosition) {
        return listPosition;
    }
  
    @Override
    // Gets a View that displays the given group.
    // This View is only for the group--the Views for the group's children
    // will be fetched using getChildView()
    public View getGroupView(int listPosition, boolean isExpanded, View convertView, ViewGroup parent) {
        String listTitle = (String) getGroup(listPosition);
        if (convertView == null) {
            LayoutInflater layoutInflater = (LayoutInflater) this.context.
                    getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = layoutInflater.inflate(R.layout.list_group, null);
        }
        TextView listTitleTextView = (TextView) convertView.findViewById(R.id.listTitle);
        listTitleTextView.setTypeface(null, Typeface.BOLD);
        listTitleTextView.setText(listTitle);
        return convertView;
    }
  
    @Override
    // Indicates whether the child and group IDs are stable across changes to the underlying data.
    public boolean hasStableIds() {
        return false;
    }
  
    @Override
    // Whether the child at the specified position is selectable.
    public boolean isChildSelectable(int listPosition, int expandedListPosition) {
        return true;
    }
}

chevron_right


  •  Below is the code for the MainActivity.java file. Comments are added inside the code to understand the code in more detail.

Java

filter_none

edit
close

play_arrow

link
brightness_4
code

import android.os.Bundle;
import android.view.View;
import android.widget.ExpandableListAdapter;
import android.widget.ExpandableListView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
  
public class MainActivity extends AppCompatActivity {
  
    ExpandableListView expandableListViewExample;
    ExpandableListAdapter expandableListAdapter;
    List<String> expandableTitleList;
    HashMap<String, List<String>> expandableDetailList;
  
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        expandableListViewExample = (ExpandableListView) findViewById(R.id.expandableListViewSample);
        expandableDetailList = ExpandableListDataItems.getData();
        expandableTitleList = new ArrayList<String>(expandableDetailList.keySet());
        expandableListAdapter = new CustomizedExpandableListAdapter(this, expandableTitleList, expandableDetailList);
        expandableListViewExample.setAdapter(expandableListAdapter);
  
        // This method is called when the group is expanded
        expandableListViewExample.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
            @Override
            public void onGroupExpand(int groupPosition) {
                Toast.makeText(getApplicationContext(), expandableTitleList.get(groupPosition) + " List Expanded.", Toast.LENGTH_SHORT).show();
            }
        });
  
        // This method is called when the group is collapsed
        expandableListViewExample.setOnGroupCollapseListener(new ExpandableListView.OnGroupCollapseListener() {
            @Override
            public void onGroupCollapse(int groupPosition) {
                Toast.makeText(getApplicationContext(), expandableTitleList.get(groupPosition) + " List Collapsed.", Toast.LENGTH_SHORT).show();
            }
        });
  
        // This method is called when the child in any group is clicked
        // via a toast method, it is shown to display the selected child item as a sample
        // we may need to add further steps according to the requirements
        expandableListViewExample.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
            @Override
            public boolean onChildClick(ExpandableListView parent, View v,
                                        int groupPosition, int childPosition, long id) {
                Toast.makeText(getApplicationContext(), expandableTitleList.get(groupPosition)
                                + " -> "
                                + expandableDetailList.get(
                                expandableTitleList.get(groupPosition)).get(
                                childPosition), Toast.LENGTH_SHORT
                ).show();
                return false;
            }
        });
    }
}

chevron_right


Output: Run On Emulator

Conclusion

ExpandableListView is a very useful mandatory feature used in many apps. In mobile app sizes and in the available space, in order to show multiple items, one should need features like ExpandableListView and ExpandableListAdapter the view can be fit perfectly. As the scrolling is available, we can keep information on many levels. The methods support expanding the header, collapsing the header, selecting the child items perfectly as seen in the emulator output. For simplicity, we have provided with Toast messages. Depends upon the requirements, we can able to add further coding to match with it.

Attention reader! Don’t stop learning now. Get hold of all the important Java and Collections concepts with the Fundamentals of Java and Java Collections Course at a student-friendly price and become industry ready.




My Personal Notes arrow_drop_up

Freelancer in Software projects using Java, Python, SQL,MongoDB technologies Can able to quickly adapt to any new technologies and can provide guidance in software projects

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.


Article Tags :
Practice Tags :


1


Please write to us at contribute@geeksforgeeks.org to report any issue with the above content.