Contents

How To Add Header Footer to ExpandableListview ChildView

1 Star2 Stars3 Stars4 Stars5 Stars (8 votes, average: 5.00 out of 5)
Loading...

 

I recently worked on a project, where I found it challenging initially to add a header and footer to the ExpandableListView childView. Here I document the solution I found to overcome the challenge.

Ho Ngoc Trang,  trangho214@gmail.com, is the author of this article and she contributes to RobustTechHouse Blog

 

XML layout files

In order to create an expandable list view with header and footer to the child view, we will need five xml layout files. The first one is for displaying the main layout containing the ExpandableListview, the second one is for group item layout, the third is for the child item layout and the other two are for header and footer of the childview.

activity_main.xml

Open activity_main.xml layout in res/layout and add the ExpandableListView element:

<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"
    tools:context=".MainActivity">

   <ExpandableListView
       android:id="@+id/elv"
       android:layout_width="match_parent"
       android:layout_height="match_parent"></ExpandableListView>

</RelativeLayout>

 

parent_row.xml

Create another xml file for list view group header and name it as parent_row.xml and copy the following content.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:background="@color/parent_background"
    android:paddingLeft="@dimen/padding_left"
    android:layout_margin="5dp"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/txtMother"
        android:layout_marginTop="10dp"
        android:textStyle="bold"
        android:layout_marginBottom="5dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <TextView
        android:id="@+id/txtFather"
        android:layout_marginBottom="10dp"
        android:textStyle="bold"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>

 

child_row.xml

Create a new layout file child_row.xml in res/layout and copy the following content.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:background="@color/child_background"
    android:paddingLeft="@dimen/padding_left"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/txtChildName"
        android:textColor="@android:color/holo_orange_dark"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"/>
    <TextView
        android:id="@+id/txtChildAge"
        android:textColor="@android:color/holo_orange_dark"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="10dp"/>
</LinearLayout>

 

child_header.xml

Create a new layout file child_header.xml in res/layout and copy the following content.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:background="@color/hf_background"
    android:paddingLeft="@dimen/padding_left">
<TextView
    android:id="@+id/txtHeader"
    android:textColor="@android:color/holo_green_light"
    android:layout_width="match_parent"
    android:gravity="center_vertical"
    android:textStyle="bold"
    android:text="Header"
    android:layout_height="50dp" />
</LinearLayout>

 

child_footer.xml

Create a new layout file child_footer.xml in res/layout and copy the following content.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:background="@color/hf_background"
    android:paddingLeft="@dimen/padding_left">
    <TextView
        android:id="@+id/txtFooter"
        android:textColor="@android:color/holo_green_light"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:gravity="center_vertical"
        android:textStyle="bold"
        android:text="Footer" />
</LinearLayout>

 

Model Classes

According to the structure of an expandable list view, we need to have at least two classes, one for the child and another one for group/parent.

ChildObject.java

ChildObject class will hold all fields displayed in the child row view.

public class ChildObject {
    public String childName;
    public int age;
    public ChildObject(String childName, int age)
    {
        this.childName = childName;
        this.age = age;
    }
}

 

ParentObject.java

ParentObject will hold all fields displayed in the group/parent row view including fields for header and footer.

public class ParentObject {
    public String mother;
    public String father;

    //Header and footer don’t need to be a String, 
    //they can be a class or whatever depend on your need.
    public String textToHeader;
    public String textToFooter;

    //Parent should have a list of their child
    public List<ChildObject> childObjects;

    public ParentObject(String mother, String father, String textToHeader, String textToFooter, List<ChildObject> childObjects)
    {
        this.mother = mother;
        this.father = father;
        this.textToFooter = textToFooter;
        this.textToHeader = textToHeader;
        this.childObjects = childObjects;
    }
}

 

Custom adapter for ExpandableListView

This is the important part of this tutorial where we actually create the header and footer for the ExpandableListView ChildView.

We are going to create a custom adapter named MyExpandableAdapter. This class is extended from BaseExpandableListAdapter, which provides required methods to render the ExpandableListView.

Create a class and name it as MyExpandableListView, then add the following code.

public class MyExpandableAdapter extends BaseExpandableListAdapter {
    Context context;
    List<ParentObject> parentObjects;

    public MyExpandableAdapter(Context context, List<ParentObject> parentObjects)
    {
        this.context = context;
        this.parentObjects = parentObjects;
    }
    @Override
    public int getGroupCount() {
        return parentObjects.size();
    }

     //Add 2 to childcount. The first row and the last row are used as header and footer to childview
    @Override
    public int getChildrenCount(int i) {
        return parentObjects.get(i).childObjects.size() +2;
    }

    @Override
    public ParentObject getGroup(int i) {
        return parentObjects.get(i);
    }

    @Override
    public ChildObject getChild(int i, int i2) {
        return parentObjects.get(i).childObjects.get(i2);
    }

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

    @Override
    public long getChildId(int i, int i2) {
        return 0;
    }

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

    @Override
    public View getGroupView(int i, boolean b, View view, ViewGroup viewGroup)
    {
        ParentObject currentParent = parentObjects.get(i);
        if(view ==null)
        {
            LayoutInflater inflater =(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            view = inflater.inflate(R.layout.parent_row,null);
        }
        TextView txtMother = (TextView)view.findViewById(R.id.txtMother);
        TextView txtFather = (TextView)view.findViewById(R.id.txtFather);
        txtMother.setText(currentParent.mother);
        txtFather.setText(currentParent.father);
        return view;
    }

    @Override
    public View getChildView(int groupPosition, int childPosition, boolean b, View view, ViewGroup viewGroup) {
        ParentObject currentParent = getGroup(groupPosition);
        LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        //the first row is used as header
        if(childPosition ==0)
        {
            view = inflater.inflate(R.layout.child_header, null);
            TextView txtHeader = (TextView)view.findViewById(R.id.txtHeader);
            txtHeader.setText(currentParent.textToHeader);
        }

        //Here is the ListView of the ChildView
        if(childPosition>0 && childPosition<getChildrenCount(groupPosition)-1)
        {
            ChildObject currentChild = getChild(groupPosition,childPosition-1);
            view = inflater.inflate(R.layout.child_row,null);
            TextView txtChildName = (TextView)view.findViewById(R.id.txtChildName);
            TextView txtChildAge = (TextView)view.findViewById(R.id.txtChildAge);
            txtChildName.setText(currentChild.childName);
            txtChildAge.setText("Age: " + String.valueOf(currentChild.age));
        }
        //the last row is used as footer
        if(childPosition == getChildrenCount(groupPosition)-1)
        {
            view = inflater.inflate(R.layout.child_footer,null);
            TextView txtFooter = (TextView)view.findViewById(R.id.txtFooter);
            txtFooter.setText(currentParent.textToFooter);
        }
        return view;
    }

    @Override
    public boolean isChildSelectable(int i, int i2) {
        return false;
    }
}

 

There are many methods in this class but there are only two of them we need to focus on:

getChildrenCount: return the count of row of child item in a specific group. Here I’ve added two extra rows to the return method. The first row will be used for header and the second row will be used for footer.

getChildView: render the child list of each group. Here we will check the child position to inflate the appropriate layout to each row. The layout of header and footer will be inflated to the first and last of childPostion and the rest will show all items of the child list.

 

Main activity and sample data for expandable list view

Once you are done with creating a custom adapter for your expandable list view, open the MainActivity class and copy the following code. In this activity I have also created sample data to display in the expandable list view.

public class MainActivity extends Activity {
    ExpandableListView elv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        LayoutInflater inflater = getLayoutInflater();
        elv = (ExpandableListView)findViewById(R.id.elv);
        elv.setOnGroupExpandListener(onGroupExpandListenser);
        MyExpandableAdapter adapter = new MyExpandableAdapter(this, getData());
        elv.setAdapter(adapter);
    }

    ExpandableListView.OnGroupExpandListener onGroupExpandListenser = new ExpandableListView.OnGroupExpandListener() {
        int previousGroup =-1;
        @Override
        public void onGroupExpand(int groupPosition) {
            if(groupPosition!= previousGroup)
                elv.collapseGroup(previousGroup);
            previousGroup = groupPosition;
        }
    };
    
   //Sample data for expandable list view.
    public List<ParentObject> getData()
    {
        List<ParentObject> parentObjects = new ArrayList<ParentObject>();
        for (int i = 0; i<20; i++)
        {
            parentObjects.add(new ParentObject("Mother " +i, "Father " +i, "Header " + i, "Footer " +i, getChildren(i)));

        }
        return parentObjects;
    }

    private List<ChildObject> getChildren(int childCount)
    {
        List<ChildObject> childObjects = new ArrayList<ChildObject>();
        for (int i =0; i<childCount; i++)
        {
            childObjects.add(new ChildObject("Child " + (i+1), 10 +i ));
        }
        return childObjects;
    }

}

 

Output

How To Add Header Footer to ExpandableListview ChildView

 

 

Conclusion

I have just showed you how I added a header and footer to the ExpandableListView ChildView. Hope you find this post useful.

The completed project can be downloaded at GitHub HeaderAndFooterForExpandableListview

 

If you like our articles, please follow and like our Facebook page where we regularly share interesting posts and check out our other blog articles.

RobustTechHouse is a leading tech company focusing on mobile app development in Singapore. If you are interested to have us work with you on your projects, you can contact us here.

Recommended Posts
Contact Us

We look forward to your messages. Please drop us a note for any enquiries and we'll get back to you, asap.

Not readable? Change text. captcha txt
Androids ManyCode Generation Process