Last Update - 10 Dec 2020

Expandable list view in android example

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.

Expandable list view in 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>

Download complete source code

Download expandable list view in android example

Did you find this page helpful? X