This is a wonderful example to show you, how to create an expandable list view in android. This is an awesome component to convert your JSON/XML data to represent in a respective manner.
I have learned already in the previous article, how to create a list view in android by Recyclerview. So now you can use an ExpandableListView component to create a list of parent and child relationships.
The expandable view that shows items in a vertically scrolling two-level list. Expandable lists are able to show an indicator beside each item to display the item's current state (the states are usually one of an expanded group, collapsed group, child, or last child).
Expandable ListView
Expandable ListView Adapter in android loads the data into the items associated with this view. Following are some important methods that are used by this class :
- setChildIndicator(Drawable): This is used to show an indicator beside each item representing the current state. If the child is the last child for a group, the state state_last will be set
- setGroupIndicator(Drawable): An indicator is drawn beside the group representing its state i.e. expanded or collapsed. If the group is empty, the state state_empty will be set. If the group is expanded, the state state_expanded will be set
- getGroupView(): It returns a view for the list group header
- getChildView(): It returns view for list child item
You can create your custom expandable list View in android by using these components. Look at the below image you can expandable listview with image and text in the android example.

Create your main layout with the help of tab layout and toolbar options.
Activity Layout
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/layoutmain">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar_search"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" />
<android.support.design.widget.TabLayout
android:id="@+id/tabs"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
app:tabGravity="center"
app:tabMode="scrollable"
/>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:layout_below="@+id/layoutmain" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/frameLayout"
android:layout_marginTop="60dp">
</FrameLayout>
</android.support.design.widget.CoordinatorLayout>
Fragment Data
fragment_data_list.xml
<?xml version="1.0" encoding="utf-8"?>
<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">
<ExpandableListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:divider="@null">
</ExpandableListView>
</RelativeLayout>
How to Start a Blog in 2020 (Beginner’s Guide)
In the adapter_list_group layout file, you can create your design, In this example, I have used the card view for the good looking header section.
Adapter List
adapter_list_group.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="25dp"
android:orientation="vertical">
<android.support.v7.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="@+id/card_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
card_view:cardCornerRadius="5dp"
card_view:cardElevation="5dp"
card_view:cardUseCompatPadding="true">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_margin="5dp"
android:orientation="vertical">
<TextView
android:id="@+id/text_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginLeft="25dp"
android:gravity="center" />
</RelativeLayout>
</android.support.v7.widget.CardView>
</RelativeLayout>
Adapter List_item
adapter_list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="25dp"
android:orientation="vertical">
<ImageView
android:id="@+id/imageView"
android:layout_width="75dp"
android:layout_height="75dp"
app:srcCompat="@drawable/circle"
tools:layout_editor_absoluteX="16dp"
tools:layout_editor_absoluteY="25dp" />
<TextView
android:id="@+id/text_desc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginLeft="90dp"
android:text="TextView"
android:textSize="18sp" />
</RelativeLayout>
Handle all ClickListeners from your DataFragment.java class. Basically, four types of ClickListeners are there:
- ExpandableListView.OnChildClickListener: You can handle ChildClickListener, This is overridden to implement the callback method that’s invoked when a child in the expanded list is clicked.
- ExpandableListView.OnGroupClickListener: This is overridden to implement the callback method that’s invoked when a group header in the expanded list is clicked.
- ExpandableListView.OnGroupCollapseListener: This is used for notifying when a group is collapsed.
- ExpandableListView.OnGroupExpandListener: This is used to notify when a group is expanded.
Data Fragment
DataFragment.java
package com.legendblogs.expandablelistview;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ExpandableListView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* Created by legendblogs on 21-01-2019.
*/
public class DataFragment extends Fragment {
private Context context;
private ExpandableListView list_view;
List<String> listDataParent;
HashMap<String, List<String>> listDataChild;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
this.context = this.getActivity();
return inflater.inflate(R.layout.fragment_data_list, container, false);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
list_view = (ExpandableListView) view.findViewById(R.id.list_view);
createListData();
// Listview Group click listener
list_view.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
@Override
public boolean onGroupClick(ExpandableListView parent, View v,
int groupPosition, long id) {
// TODO GroupClickListener work
return false;
}
});
// Listview Group expanded listener
list_view.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
@Override
public void onGroupExpand(int groupPosition) {
// TODO GroupExpandListener work
}
});
// Listview Group collasped listener
list_view.setOnGroupCollapseListener(new ExpandableListView.OnGroupCollapseListener() {
@Override
public void onGroupCollapse(int groupPosition) {
// TODO GroupCollapseListener work
}
});
// Listview on child click listener
list_view.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
@Override
public boolean onChildClick(ExpandableListView parent, View v,
int groupPosition, int childPosition, long id) {
Toast.makeText( context,
"wow, this is - "+listDataChild.get(listDataParent.get(groupPosition)).get(childPosition),
Toast.LENGTH_SHORT).show();
return false;
}
});
}
private void createListData() {
listDataParent = new ArrayList<String>();
listDataChild = new HashMap<String, List<String>>();
// Adding child data
listDataParent.add("Colors");
listDataParent.add("Fruits");
listDataParent.add("Animals");
// Adding child data List one
List<String> colors = new ArrayList<String>();
colors.add("Red");
colors.add("Green");
colors.add("Blue");
colors.add("Yellow");
colors.add("Blue");
// Adding child data List two
List<String> fruits = new ArrayList<String>();
fruits.add("Apples");
fruits.add("Bananas");
fruits.add("Apricots");
fruits.add("Cherries");
fruits.add("Elderberry");
fruits.add("Dates");
// Adding child data List three
List<String> animals = new ArrayList<String>();
animals.add("Dog");
animals.add("Cat");
animals.add("Elephant");
animals.add("horse");
listDataChild.put(listDataParent.get(0), colors); // Header, Child data
listDataChild.put(listDataParent.get(1), fruits); // Header, Child data
listDataChild.put(listDataParent.get(2), animals); // Header, Child data
ExpandableListAdapter listAdapter = new ExpandableListAdapter(context, listDataParent, listDataChild);
list_view.setAdapter(listAdapter);
}
}
Tab Pager Adapter
TabPagerAdapter.java
package com.legendblogs.expandablelistview;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
/**
* Created by legendblogs on 21-01-2019.
*/
public class TabPagerAdapter extends FragmentPagerAdapter {
public TabPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
Fragment fragment = null;
if (position == 0)
{
fragment = new DataFragment();
}
return fragment;
}
@Override
public int getCount() {
return 1;
}
@Override
public CharSequence getPageTitle(int position) {
String title = null;
if (position == 0)
{
title = "List";
}
return title;
}
}
Expandable List Adapter
ExpandableListAdapter.java
package com.legendblogs.expandablelistview;
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;
/**
* Created by legendblogs on 21-01-2019.
*/
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.adapter_list_item, null);
}
TextView txtListChild = (TextView) convertView
.findViewById(R.id.text_desc);
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.adapter_list_group, null);
}
TextView lblListHeader = (TextView) convertView
.findViewById(R.id.text_title);
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;
}
}
Main Activity
MainActivity.java
package com.legendblogs.expandablelistview;
import android.support.design.widget.TabLayout;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.view.View;
/**
* Created by legendblogs on 21-01-2019.
*/
public class MainActivity extends AppCompatActivity {
private Toolbar toolbar;
private TabPagerAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = (Toolbar) findViewById(R.id.toolbar_search);
if(getSupportActionBar() == null) {
setSupportActionBar(toolbar);
}else toolbar.setVisibility(View.GONE);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
ViewPager viewPager = (ViewPager) findViewById(R.id.viewPager);
adapter = new TabPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(adapter);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(viewPager);
}
@Override
public void onBackPressed() {
super.onBackPressed();
}
}
Gradle File Changes
This is the most important section because, in the Gradle file, you need to add expandable listview dependency.
implementation 'com.android.support:design:28.0.0'
build.gradle
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.legendblogs.expandablelistview"
minSdkVersion 15
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support:design:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
Android Manifest
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.legendblogs.expandablelistview">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Write a comment