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.
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
< resources > <!-- Default screen margins, per the Android Design guidelines. --> < dimen name = "activity_horizontal_margin" >16dp</ dimen > < dimen name = "activity_vertical_margin" >16dp</ dimen > </ resources > |
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
<!-- RelativeLayout places the components vertically one by one. Necessary parameters also specified so that elegant output can be seen --> < 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" 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. --> |
- 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
<? 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" > < 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 > |
- 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
<? 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" > < 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 > |
- 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
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 respectively. // 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; } } |
- 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
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 ; } } |
- Below is the code for the MainActivity.java file. Comments are added inside the code to understand the code in more detail.
Java
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 ; } }); } } |
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.
Contact Us