ExpandableListView With Example In Android Studio

ExpandableListView With Example In Android Studio

In Android, ExpandableListView is a View that shows items in a vertically scrolling two level list. Different from the listview by allowing two level groups which can individually be expanded to show its children. Each group can be expanded or collapsed individually to show or hide its children items.
ExpandableListView in Android
We can attach listeners events to the ExpandableListView to listen for OnClick or any other events on the Group or the individual children.  Adapters are used to supply or control the data that will be displayed in an ExpandableListView.
Important Note: You cannot use the value wrap_content for the height attribute of a ExpandableListView in XML if the parent’s size is not strictly specified. In other words we mean if the parent were ScrollView then you could not specify wrap_content since it can be of any length. However, you can use wrap content if the ExpandableListView parent has a specific size, such as 200 pixels.
ExpandableListView code in XML:
<ExpandableListView
android:id="@+id/simpleExpandableListView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
ExpandableListView In XML Android

Attributes of ExpandableListView In Android

Now let’s we discuss about some important attributes that helps us to configure a ExpandableListView in XML file(layout).
1. id: id is an attribute used to uniquely identify a Expandable List View.
<ExpandableListView
android:id="@+id/simpleExpandableListView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/> <!--  id of an attribute used to uniquely identify a expandable list view -->
2. divider: This is a drawable or color to draw between different group list items.
Below we draw red color divider between different group items.
<ExpandableListView
android:id="@+id/simpleExpandableListView"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:divider="#f00"
android:dividerHeight="1dp" /> "/> <!--  red color divider with 1dp height between the groups items of  expandable list view -->
Divider in ExpandableListView Android
3. dividerHeight: This specify the height of the divider between group list items. This could be in dp ( density pixel ), sp(scale independent pixel) or px ( pixel ).
In above example of divider we also set the divider height 1dp between the list items. The height should be in dp, sp or px.
4. listSelector: This property is used to set the selector of the expandable list View. It is generally orange or Sky blue color mostly but you can also define your own custom color or an image as a list selector as per your design.
Below selector color is green, when you select any list item then that item’s background color is green.
<ExpandableListView
android:id="@+id/simpleExpandableListView"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:divider="#f00"
android:dividerHeight="1dp"
android:listSelector="#0f0" /> <!--  green color for the list selector item -->
listSelector in ExpandableListView Android
5. childDivider: This is a drawable or color to draw between different child list items of a expandable list view.
Below we draw green color divider between different child items of a group.
<ExpandableListView
    android:id="@+id/simpleExpandableListView"
    android:layout_width="match_parent"
    android:layout_height="fill_parent"
    android:divider="#f00"
    android:dividerHeight="1dp"
    android:childDivider="#0f0" />  <!--  green color divider between the child items of  expandable list view -->
The below image is from the ExpandableListView example which is explained at the end of this post. In this we have set green color as Child divider and red color as divider. The reason we have used this example image because we need fill data using Adapter to show you childDivider attribute in action.
childDivider in ExpandableListView Android
6. padding: padding attribute is used to set the padding from left, right, top or bottom.
  • paddingRight: set the padding from the right side of the expandable list view.
  • paddingLeft: set the padding from the left side of the Progress bar.
  • paddingTop: set the padding from the top side of the expandable list view.
  • paddingBottom: set the padding from the bottom side of the expandable list view.
  • Padding: set the padding from the all side’s of the expandable list view.
Below we set the 50dp padding from all the side’s of the expandable list view.
<ExpandableListView
android:id="@+id/simpleExpandableListView"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:divider="#f00"
android:dividerHeight="2dp"
android:childDivider="#0f0"
android:padding="50dp" /> <!--  50 dp padding from all the sides of a expandable list view -->
padding in ExpandableListView Android

Adapter Used In ExpandableListView In Android:

An adapter is a bridge between UI component and data source that helps us to fill data in UI component. It holds the data and send the data to Adapter view then view can takes the data from the adapter view and shows the data on different views like as ExpandableListView or other Views. The implementation of this interface will provide access to the data of the children (categorized by groups), and also instantiate views for the children and groups.
In Android for supplying data in an ExpandableListView following adapters are used.
1. ExpandableListAdapter
2. BaseExpandableListAdapter
3. SimpleExpandableListAdapter
Now we explain these three adapters in detail:
1. ExpandableListAdapter:
ExpandableListAdapter is an Adapter that links a ExpandableListView with the underlying data. The implementation of this interface will provide the data for the children and also initiate the views for the children and groups.  For customization of list we need to implement ExpandableListAdapter in our custom adapter.
Below is the example code of ExpandableListAdapter in which we create CustomAdapter class and then implements ExpandableListAdapter in that class.
public class CustomAdapter implements ExpandableListAdapter {
@Override
public void registerDataSetObserver(DataSetObserver observer) {

}

@Override
public void unregisterDataSetObserver(DataSetObserver observer) {

}

@Override
public int getGroupCount() {
return 0;
}

@Override
public int getChildrenCount(int groupPosition) {
return 0;
}

@Override
public Object getGroup(int groupPosition) {
return null;
}

@Override
public Object getChild(int groupPosition, int childPosition) {
return null;
}

@Override
public long getGroupId(int groupPosition) {
return 0;
}

@Override
public long getChildId(int groupPosition, int childPosition) {
return 0;
}

@Override
public boolean hasStableIds() {
return false;
}

@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
return null;
}

@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
return null;
}

@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return false;
}

@Override
public boolean areAllItemsEnabled() {
return false;
}

@Override
public boolean isEmpty() {
return false;
}

@Override
public void onGroupExpanded(int groupPosition) {

}

@Override
public void onGroupCollapsed(int groupPosition) {

}

@Override
public long getCombinedChildId(long groupId, long childId) {
return 0;
}

@Override
public long getCombinedGroupId(long groupId) {
return 0;
}
}
2. BaseExpandableListAdapter:
BaseExpandableListAdapter is a base class for the expandable list adapter used to provide data and Views from some data to ExpandableListView. For Creating a custom ExpandableListView we need to create a custom class and then extends BaseExpandableListAdapter class in that class.
Below is an example code of BaseExpandableListAdapter in which we create custom adapter class and then extends BaseExpandableListAdapter in that class.
public class CustomAdapter extends BaseExpandableListAdapter {

@Override
public int getGroupCount() {
return 0;
}

@Override
public int getChildrenCount(int groupPosition) {
return 0;
}

@Override
public Object getGroup(int groupPosition) {
return null;
}

@Override
public Object getChild(int groupPosition, int childPosition) {
return null;
}

@Override
public long getGroupId(int groupPosition) {
return 0;
}

@Override
public long getChildId(int groupPosition, int childPosition) {
return 0;
}

@Override
public boolean hasStableIds() {
return false;
}

@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
return null;
}

@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
return null;
}

@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return false;
}
}
Read BaseExpandableListAdapter With Example In Android Studio for explanation of all these function.
3. SimpleExpandableListAdapter:
SimpleExpandableListAdapter is an adapter that is used to map the static data to group and child views defined in our XML ( layout ) file. We can separately specify the data backing to the group as a List of Maps. Each entry in a ArrayList corresponds to one group in the Expandable List. The maps contains the data for each row. We can also specify an XML file that defines the views used to display a group, and a mapping from keys in the Map to specific views. This process is similar for a child, except it is one level deeper so the data backing is specified as a List<list>, where the first List is corresponds to the group of the child and the second List corresponds to the position of the child within that group, and finally the Map holds the data for the particular child.
public SimpleExpandableListAdapter (Context context, List<? extends Map<String, ?>> groupData, int groupLayout, String[]groupFrom, int[] groupTo, List<? extends List<? extends Map<String, ?>>> childData, int childLayout, String[] childFrom, int[] childTo)
Read SimpleExpandableListAdapter tutorial for explanation of all these parameter.

ExpandableListView using BaseExpandableListAdapter Example In Android Studio

Below is the example of ExpandableListView in android where we display an expandable list with subject name and their topics. In this example we display subject names as Group items and their topic names as child items for a particular group. In this we implement setOnChildClickListener() and setOnGroupClickListener() events and whenever a user clicks on a child or a group item the name of the item is displayed by using a Toast.
Below you can download code, see final output and step by step explanation of Example in Android Studio:
Download Code
ExpandableListView Example In Android Studio
Step 1: Create a new project and name it ExpandableListViewExample.
Step 2: Open res -> layout ->activity_main.xml (or) main.xml and add following code:
In this step we open an XML file and add the code for displaying a ExpandableListView by using its different attributes.
<?xml version="1.0" encoding="UTF-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <ExpandableListView
        android:id="@+id/simpleExpandableListView"
        android:layout_width="match_parent"
        android:layout_height="fill_parent"
        android:divider="#f00"
        android:childDivider="#0f0"
        android:dividerHeight="1dp" />

</RelativeLayout>
Step 3: Create a new xml file for group items Open res -> layout -> group_items.xml and add following code:
In this step we add the code for displaying a TextView subject names.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="55dip"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/heading"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingLeft="35sp"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:textStyle="bold" />

</LinearLayout>
Step 4: Create a new xml file for group items Open res -> layout -> child_items.xml and add following code:
In this step we add the code for displaying two TextView i.e. one for sequence of topics and another for topic name
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"
    android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android">

    <TextView
        android:id="@+id/sequence"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:paddingLeft="35sp"
        android:textAppearance="?android:attr/textAppearanceMedium" />

    <TextView
        android:id="@+id/childItem"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_toRightOf="@id/sequence"
        android:textAppearance="?android:attr/textAppearanceMedium" />

</RelativeLayout>
Step 5: Open   src -> package -> MainActivity.Java
In this step we open MainActivity and add the code to initiate the ExpandableListView and add the data to lists for displaying in an ExpandableListView using model classes and then set the adapter which fills the data in the ExpandableListView. In this we implement setOnChildClickListener() and setOnGroupClickListener() events. Whenever a user clicks on a child or a group item the name of the item is display by using a Toast.
package example.abhiandroid.expandablelistviewexample;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ExpandableListView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.LinkedHashMap;

public class MainActivity extends AppCompatActivity{

    private LinkedHashMap<String, GroupInfo> subjects = new LinkedHashMap<String, GroupInfo>();
    private ArrayList<GroupInfo> deptList = new ArrayList<GroupInfo>();

    private CustomAdapter listAdapter;
    private ExpandableListView simpleExpandableListView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // add data for displaying in expandable list view
        loadData();

        //get reference of the ExpandableListView
        simpleExpandableListView = (ExpandableListView) findViewById(R.id.simpleExpandableListView);
        // create the adapter by passing your ArrayList data
        listAdapter = new CustomAdapter(MainActivity.this, deptList);
        // attach the adapter to the expandable list view
        simpleExpandableListView.setAdapter(listAdapter);

        //expand all the Groups
        expandAll();

        // setOnChildClickListener listener for child row click
        simpleExpandableListView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
            @Override
            public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
                //get the group header
                GroupInfo headerInfo = deptList.get(groupPosition);
                //get the child info
                ChildInfo detailInfo =  headerInfo.getProductList().get(childPosition);
                //display it or do something with it
                Toast.makeText(getBaseContext(), " Clicked on :: " + headerInfo.getName()
                        + "/" + detailInfo.getName(), Toast.LENGTH_LONG).show();
                return false;
            }
        });
        // setOnGroupClickListener listener for group heading click
        simpleExpandableListView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
            @Override
            public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
                //get the group header
                GroupInfo headerInfo = deptList.get(groupPosition);
                //display it or do something with it
                Toast.makeText(getBaseContext(), " Header is :: " + headerInfo.getName(),
                        Toast.LENGTH_LONG).show();

                return false;
            }
        });


    }

    //method to expand all groups
    private void expandAll() {
        int count = listAdapter.getGroupCount();
        for (int i = 0; i < count; i++){
            simpleExpandableListView.expandGroup(i);
        }
    }

    //method to collapse all groups
    private void collapseAll() {
        int count = listAdapter.getGroupCount();
        for (int i = 0; i < count; i++){
            simpleExpandableListView.collapseGroup(i);
        }
    }

    //load some initial data into out list
    private void loadData(){

        addProduct("Android","ListView");
        addProduct("Android","ExpandableListView");
        addProduct("Android","GridView");

        addProduct("Java","PolyMorphism");
        addProduct("Java","Collections");

    }



    //here we maintain our products in various departments
    private int addProduct(String department, String product){

        int groupPosition = 0;

        //check the hash map if the group already exists
        GroupInfo headerInfo = subjects.get(department);
        //add the group if doesn't exists
        if(headerInfo == null){
            headerInfo = new GroupInfo();
            headerInfo.setName(department);
            subjects.put(department, headerInfo);
            deptList.add(headerInfo);
        }

        //get the children for the group
        ArrayList<ChildInfo> productList = headerInfo.getProductList();
        //size of the children list
        int listSize = productList.size();
        //add to the counter
        listSize++;

        //create a new child and add that to the group
        ChildInfo detailInfo = new ChildInfo();
        detailInfo.setSequence(String.valueOf(listSize));
        detailInfo.setName(product);
        productList.add(detailInfo);
        headerInfo.setProductList(productList);

        //find the group position inside the list
        groupPosition = deptList.indexOf(headerInfo);
        return groupPosition;
    }

}
Step 6: Create a New Class Open -> package – > GroupInfo.Java and add the following code.
In this step, we create a class for setting and getting the group item name and child items info according to a particular group. GroupInfo is a model class used to set the name of the group item and child items information from your main activity and then get the information within Adapter class. Finally set the value to ExpandableListView.
package example.abhiandroid.expandablelistviewexample;

import java.util.ArrayList;

public class GroupInfo {

    private String name;
    private ArrayList<ChildInfo> list = new ArrayList<ChildInfo>();

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public ArrayList<ChildInfo> getProductList() {
        return list;
    }

    public void setProductList(ArrayList<ChildInfo> productList) {
        this.list = productList;
    }

}
Step 7: Create a New Class Open -> package – > ChildInfo.Java and add the following code.
In this step, we create a class for setting and getting the name and sequence for the child items. ChildInfo is a model class used to set the name of the child item and the sequence of the child item from your main activity and then get the name and sequence within adapter class. Finally set the value to expandable list view.
package example.abhiandroid.expandablelistviewexample;

public class ChildInfo {

    private String sequence = "";
    private String name = "";

    public String getSequence() {
        return sequence;
    }

    public void setSequence(String sequence) {
        this.sequence = sequence;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}
Step 8: Create a New Class Open -> package – > CustomAdapter.Java and add the following code.
In this step, we create a CustomAdapter class and then extends BaseExpandableListAdapter in that class. Finally set the data in the ExpandableListView from GroupInfo and  ChildInfo model class.
package example.abhiandroid.expandablelistviewexample;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.TextView;

import java.util.ArrayList;


/**
 * Created by Gourav on 08-03-2016.
 */
public class CustomAdapter extends BaseExpandableListAdapter {

    private Context context;
    private ArrayList<GroupInfo> deptList;

    public CustomAdapter(Context context, ArrayList<GroupInfo> deptList) {
        this.context = context;
        this.deptList = deptList;
    }

    @Override
    public Object getChild(int groupPosition, int childPosition) {
        ArrayList<ChildInfo> productList = deptList.get(groupPosition).getProductList();
        return productList.get(childPosition);
    }

    @Override
    public long getChildId(int groupPosition, int childPosition) {
        return childPosition;
    }

    @Override
    public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
                             View view, ViewGroup parent) {

        ChildInfo detailInfo = (ChildInfo) getChild(groupPosition, childPosition);
        if (view == null) {
            LayoutInflater infalInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            view = infalInflater.inflate(R.layout.child_items, null);
        }

        TextView sequence = (TextView) view.findViewById(R.id.sequence);
        sequence.setText(detailInfo.getSequence().trim() + ". ");
        TextView childItem = (TextView) view.findViewById(R.id.childItem);
        childItem.setText(detailInfo.getName().trim());

        return view;
    }

    @Override
    public int getChildrenCount(int groupPosition) {

        ArrayList<ChildInfo> productList = deptList.get(groupPosition).getProductList();
        return productList.size();

    }

    @Override
    public Object getGroup(int groupPosition) {
        return deptList.get(groupPosition);
    }

    @Override
    public int getGroupCount() {
        return deptList.size();
    }

    @Override
    public long getGroupId(int groupPosition) {
        return groupPosition;
    }

    @Override
    public View getGroupView(int groupPosition, boolean isLastChild, View view,
                             ViewGroup parent) {

        GroupInfo headerInfo = (GroupInfo) getGroup(groupPosition);
        if (view == null) {
            LayoutInflater inf = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            view = inf.inflate(R.layout.group_items, null);
        }

        TextView heading = (TextView) view.findViewById(R.id.heading);
        heading.setText(headerInfo.getName().trim());

        return view;
    }

    @Override
    public boolean hasStableIds() {
        return true;
    }

    @Override
    public boolean isChildSelectable(int groupPosition, int childPosition) {
        return true;
    }

}
Output:
Now run the App and you will see main topics and sub-topics listed in ExpandableListView.

No comments:

Post a Comment

Note: only a member of this blog may post a comment.

How to extract filename from Uri?

Now, we can extract filename with and without extension :) You will convert your bitmap to uri and get the real path of your file. Now w...