• (2 Pages)
  • +
  • 1
  • 2

How to get started with ExpandableListView

#1 EndLessMind  Icon User is offline

  • These are the droids you're looking for
  • member icon

Reputation: 194
  • View blog
  • Posts: 1,099
  • Joined: 13-March 09

Posted 12 March 2012 - 05:21 PM

Hello everyone, and welcome to another tutorial on Android development.
This time i want to teach you how to get started with the ExpandableListView
This can, as well as my last tutorial also save screen-area

Let's get started

Introduction
ExpandableListView is great of when you want to sort lists in to categories.
Like: If you have many movies, you might want to categories them by genre, so you can navigate trough them easier.
Or maybe you want to make an app to handle you bill's. Then you might want to have categories like "electricity","loans" etc.
This is just 2 of many ways you can use the ExpandableListView.

Preparing the environment
Lets first create a new Android project and name it "com.tutorial.expandListView"
and the build target for Android 2.2, and next set the following:
Application name: Tutorial expandListView
Package name: com.tutorial.expandListView
Create Activity (Checked): MainActivity
Then press Finish.

Basic layout
On to the layout.
The layout is fairly simple.
Go to res->layout and open the file main.xml
There you'll only find a LinearLayout and a TextView.
Remove the TextView and add the following
            <ExpandableListView
                android:id="@+id/ExpList"
                android:layout_height="match_parent"
                android:layout_width="match_parent"
                android:groupIndicator="@null" />   


So now, the code should look like this
<?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="fill_parent"
    android:orientation="vertical" >

            <ExpandableListView
                android:id="@+id/ExpList"
                android:layout_height="match_parent"
                android:layout_width="match_parent"
                android:groupIndicator="@null" />   

</LinearLayout>

Lets move on


Creating our classes
To handle the data we are going to create 2 classes.
Lets start out by creating a new package in the src-folder and name it com.tutorial.expandListView.Classes

In this package we are going to create 2 class-files, one named ExpandListChild.java, and the other name ExpandListGroup.java

The ExpandListChild.java is going to hold 2 values, Name and Tag (Tag has no purposes now, but might later)
package com.tutorial.expandListView.Classes;

public class ExpandListChild {

	private String Name;
	private String Tag;
	
	public String getName() {
		return Name;
	}
	public void setName(String Name) {
		this.Name = Name;
	}
	public String getTag() {
		return Tag;
	}
	public void setTag(String Tag) {
		this.Tag = Tag;
	}
}



and the ExpandListGroup.java is going to hold 2 values called Name and Items
package com.tutorial.expandListView.Classes;

import java.util.ArrayList;

public class ExpandListGroup {
 
	private String Name;
	private ArrayList<ExpandListChild> Items;
	
	public String getName() {
		return Name;
	}
	public void setName(String name) {
		this.Name = name;
	}
	public ArrayList<ExpandListChild> getItems() {
		return Items;
	}
	public void setItems(ArrayList<ExpandListChild> Items) {
		this.Items = Items;
	}
	
	
}



So, that code is very simple. We are only getting and setting 2 values in each class.

The Adapter
Here is the tricky part. the ExpandListAdapter, this is the code that will handle the Items so they can be displayed.

For this part we are going to create a new package, and we are naming it com.tutorial.expandListView.Adapter
In this package we are going to create a new class called ExpandListAdapter.java

Here is the code for that class
package com.tutorial.expandListView.Adapter;

import java.util.ArrayList;

import com.tutorial.expandListView.R;
import com.tutorial.expandListView.Classes.*;

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

public class ExpandListAdapter extends BaseExpandableListAdapter {

	private Context context;
	private ArrayList<ExpandListGroup> groups;
	public ExpandListAdapter(Context context, ArrayList<ExpandListGroup> groups) {
		this.context = context;
		this.groups = groups;
	}
	
	public void addItem(ExpandListChild item, ExpandListGroup group) {
		if (!groups.contains(group)) {
			groups.add(group);
		}
		int index = groups.indexOf(group);
		ArrayList<ExpandListChild> ch = groups.get(index).getItems();
		ch.add(item);
		groups.get(index).setItems(ch);
	}
	public Object getChild(int groupPosition, int childPosition) {
		// TODO Auto-generated method stub
		ArrayList<ExpandListChild> chList = groups.get(groupPosition).getItems();
		return chList.get(childPosition);
	}

	public long getChildId(int groupPosition, int childPosition) {
		// TODO Auto-generated method stub
		return childPosition;
	}

	public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View view,
			ViewGroup parent) {
		ExpandListChild child = (ExpandListChild) getChild(groupPosition, childPosition);
		if (view == null) {
			LayoutInflater infalInflater = (LayoutInflater) context.getSystemService(context.LAYOUT_INFLATER_SERVICE);
			view = infalInflater.inflate(R.layout.expandlist_child_item, null);
		}
		TextView tv = (TextView) view.findViewById(R.id.tvChild);
		tv.setText(child.getName().toString());
		tv.setTag(child.getTag());
		// TODO Auto-generated method stub
		return view;
	}

	public int getChildrenCount(int groupPosition) {
		// TODO Auto-generated method stub
		ArrayList<ExpandListChild> chList = groups.get(groupPosition).getItems();

		return chList.size();

	}

	public Object getGroup(int groupPosition) {
		// TODO Auto-generated method stub
		return groups.get(groupPosition);
	}

	public int getGroupCount() {
		// TODO Auto-generated method stub
		return groups.size();
	}

	public long getGroupId(int groupPosition) {
		// TODO Auto-generated method stub
		return groupPosition;
	}

	public View getGroupView(int groupPosition, boolean isLastChild, View view,
			ViewGroup parent) {
		ExpandListGroup group = (ExpandListGroup) getGroup(groupPosition);
		if (view == null) {
			LayoutInflater inf = (LayoutInflater) context.getSystemService(context.LAYOUT_INFLATER_SERVICE);
			view = inf.inflate(R.layout.expandlist_group_item, null);
		}
		TextView tv = (TextView) view.findViewById(R.id.tvGroup);
		tv.setText(group.getName());
		// TODO Auto-generated method stub
		return view;
	}

	public boolean hasStableIds() {
		// TODO Auto-generated method stub
		return true;
	}

	public boolean isChildSelectable(int arg0, int arg1) {
		// TODO Auto-generated method stub
		return true;
	}

}



So, basically. This code gets each group and draws it on the screen in the correct order. Then, when you expand one of them, it gets the Childs and draws them on the screen in the correct order.
This code also sets the displayed text for each group and child.

Group and child layout
wooh.. thats a bit of code. But we are not finished just yet.
Now we are going to create 2 new xml-layouts that are going to define the layout of the groups and the childs.

Lets go into the res->layout and add 2 new xml files named expandlist_child_item.xml and expandlist_group_item.xml
The code for each of them are very very simple.
For the expandlist_child_item.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="55dip"
    android:background="@color/ExpandChildBackground"
    android:orientation="vertical" >


    <TextView
        android:id="@+id/tvChild"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textColor="@color/Black"
        android:textSize="17dip" />

</LinearLayout>

And for the expandlist_group_item.xml
<?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:background="@color/ExpandGroupBackground"
    android:orientation="vertical" >


    <TextView
        android:id="@+id/tvGroup"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginRight="15dp"
        android:textColor="@color/Black"
        android:textSize="17dip" />

</LinearLayout>


Now, go in to res->values and open the strings.xml
Here we are going to add 3 colors.
Black, ExpandChildBackground and ExpandGroupBackground
the Value of Black is #000000
The value of ExpandChildBackground is #FFAFABAB
And the value of ExpandGroupBackground is #FF7C7C7C

Putting it all together
So, we got all the code we need.
Now lets put it together.

Go in to src->com.tutorial.expandListView and open the MainActivity.java
This is the code you'll see.
It's a auto-generated code.
package com.tutorial.expandListView;

import android.app.Activity;
import android.os.Bundle;

public class MainActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
}


We, are going to change it to this
package com.tutorial.expandListView;

import java.util.ArrayList;

import com.tutorial.expandListView.R;
import com.tutorial.expandListView.Adapter.ExpandListAdapter;
import com.tutorial.expandListView.Classes.*;

import android.app.Activity;
import android.os.Bundle;
import android.widget.ExpandableListView;

public class MainActivity extends Activity {
    /** Called when the activity is first created. */
	private ExpandListAdapter ExpAdapter;
	private ArrayList<ExpandListGroup> ExpListItems;
	private ExpandableListView ExpandList;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        ExpandList = (ExpandableListView) findViewById(R.id.ExpList);
        ExpListItems = SetStandardGroups();
        ExpAdapter = new ExpandListAdapter(MainActivity.this, ExpListItems);
        ExpandList.setAdapter(ExpAdapter);
    }
    
    public ArrayList<ExpandListGroup> SetStandardGroups() {
    	ArrayList<ExpandListGroup> list = new ArrayList<ExpandListGroup>();
    	ArrayList<ExpandListChild> list2 = new ArrayList<ExpandListChild>();
        ExpandListGroup gru1 = new ExpandListGroup();
        gru1.setName("Comedy");
        ExpandListChild ch1_1 = new ExpandListChild();
        ch1_1.setName("A movie");
        ch1_1.setTag(null);
        list2.add(ch1_1);
        ExpandListChild ch1_2 = new ExpandListChild();
        ch1_2.setName("An other movie");
        ch1_2.setTag(null);
        list2.add(ch1_2);
        ExpandListChild ch1_3 = new ExpandListChild();
        ch1_3.setName("And an other movie");
        ch1_3.setTag(null);
        list2.add(ch1_3);
        gru1.setItems(list2);
        list2 = new ArrayList<ExpandListChild>();
        
        ExpandListGroup gru2 = new ExpandListGroup();
        gru2.setName("Action");
        ExpandListChild ch2_1 = new ExpandListChild();
        ch2_1.setName("A movie");
        ch2_1.setTag(null);
        list2.add(ch2_1);
        ExpandListChild ch2_2 = new ExpandListChild();
        ch2_2.setName("An other movie");
        ch2_2.setTag(null);
        list2.add(ch2_2);
        ExpandListChild ch2_3 = new ExpandListChild();
        ch2_3.setName("And an other movie");
        ch2_3.setTag(null);
        list2.add(ch2_3);
        gru2.setItems(list2);
        list.add(gru1);
        list.add(gru2);
        
        return list;
    }

}

Now we set some default items to a list, load the list to the Adapter, and apply the adapter to the ExpandableListView

The finished product of this tutorial will look like this
Attached Image
This will work great together with the slide-in menu i showed in my last tutorial
Hope this can be helpful, and i hope you the best of luck, making android software.

Cheers, EndLessMind

Is This A Good Question/Topic? 3
  • +

Replies To: How to get started with ExpandableListView

#2 EndLessMind  Icon User is offline

  • These are the droids you're looking for
  • member icon

Reputation: 194
  • View blog
  • Posts: 1,099
  • Joined: 13-March 09

Posted 29 March 2012 - 05:33 PM

Forgot to attach the source-code, and for some reason i can't edit the tutorial, so here is it :)

Source-code to this tutorial:
Attached File  com.tutorial.expandListView.zip (67.25K)
Number of downloads: 4688
Was This Post Helpful? 0
  • +
  • -

#3 jstylez  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 4
  • Joined: 15-July 12

Posted 15 July 2012 - 10:53 PM

great tutorials!

but im in need of a little assistance, im having a little trouble merging the 2 together

i did this separate to your first tutorial then i tried implementing it in but i must have some of the code in wrong place, im not to sure
below is a link to what i have done, if you would be able to point me in the right direction it would be much appreciated!

https://dl.dropbox.c...al.menuList.zip

thanks
Was This Post Helpful? 0
  • +
  • -

#4 EndLessMind  Icon User is offline

  • These are the droids you're looking for
  • member icon

Reputation: 194
  • View blog
  • Posts: 1,099
  • Joined: 13-March 09

Posted 16 July 2012 - 01:35 PM

Hi.
I've looked at your code, and i found that i think is your problem.
This is what you have in the onCreate()
		
		MenuList = (LinearLayout) findViewById(R.id.ExpList);

You are setting the LinearLayout to the same widget as the ExpandableListView.
so the correct code would be
MenuList = (LinearLayout) findViewById(R.id.SlideMenu);


but only after you change your layout to
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >


    <LinearLayout
        android:id="@+id/linearLayout1"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    <LinearLayout
        android:id="@+id/SlideMenu"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <ExpandableListView
                android:id="@+id/ExpList"
                android:layout_height="match_parent"
                android:layout_width="match_parent"
                android:groupIndicator="@null" /> 
</LinearLayout>

            <LinearLayout
                android:id="@+id/linearLayout3"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_weight="0.99"
                android:orientation="vertical" >
  <TableRow
                    android:id="@+id/tableRow1"
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical" >

    <LinearLayout
        android:id="@+id/linearLayout5"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal" >
"
                    

        

        <Button
            android:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Menu"
            android:layout_marginTop="2dp" />
    </LinearLayout>

                </TableRow>

</LinearLayout>
</LinearLayout>
</FrameLayout>


That should to the trick :)

Cheers
Was This Post Helpful? 1
  • +
  • -

#5 jstylez  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 4
  • Joined: 15-July 12

Posted 16 July 2012 - 06:41 PM

Great! Thankyou it is working again but it seems to be displaying the list over the top, so there is no button to animate the menu across, i tried moving the expandlist commands around in the oncreate but then it was just a black screen with nothing.

Has it got more to do with its placement within the xml or is the java?

Thanks again!
Jase.
Was This Post Helpful? 0
  • +
  • -

#6 EndLessMind  Icon User is offline

  • These are the droids you're looking for
  • member icon

Reputation: 194
  • View blog
  • Posts: 1,099
  • Joined: 13-March 09

Posted 16 July 2012 - 06:45 PM

That might be my bad :P That's something wring with the xml
I didn't check it before i posted it ^^


Please vote posts that's helpful :)
Was This Post Helpful? 1
  • +
  • -

#7 jstylez  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 4
  • Joined: 15-July 12

Posted 16 July 2012 - 07:31 PM

thanks, ill try it out when i get the chance and let you know how i go ^_^
Was This Post Helpful? 0
  • +
  • -

#8 jstylez  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 4
  • Joined: 15-July 12

Posted 17 July 2012 - 02:35 AM

still having a little trouble, moving it around in the xml, im still only getting the list appear straight away when the application launches or just a black screen :/
Was This Post Helpful? 0
  • +
  • -

#9 EndLessMind  Icon User is offline

  • These are the droids you're looking for
  • member icon

Reputation: 194
  • View blog
  • Posts: 1,099
  • Joined: 13-March 09

Posted 17 July 2012 - 05:43 AM

Try something like this
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >
>    <LinearLayout
        android:id="@+id/linearLayout22"
        android:layout_width="match_parent"
        android:layout_height="fill_parent" >
        
        <LinearLayout
            android:id="@+id/SlideMenu"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:background="@drawable/hz_background_gradient"
            android:orientation="vertical" >

            <ExpandableListView
                android:id="@+id/ExpandList"
                android:layout_height="match_parent"
                android:layout_width="match_parent"
                android:groupIndicator="@null" />                                    
        </LinearLayout>
        
    <LinearLayout
        android:id="@+id/linearLayout53"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

        <TableRow
                    android:id="@+id/tableRow12"
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:background="@drawable/hz_background_gradient"
                    android:orientation="horizontal" >


    <LinearLayout
        android:id="@+id/linearLayout56"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >
"


        <Button
            android:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="2dp"
            android:text="Search" />

        <EditText
            android:id="@+id/tbxSearch"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:layout_marginTop="2dp"
            android:layout_weight="3.21"
            android:ems="10"
            android:singleLine="true" >

            <requestFocus />
        </EditText>
    </LinearLayout>

                </TableRow>

 </LinearLayout>
                 </LinearLayout>

</FrameLayout>

:)
Was This Post Helpful? 0
  • +
  • -

#10 CptPoo  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 29-July 12

Posted 29 July 2012 - 10:07 AM

Hello, thank you for this awesome article, it is helping me understand a lot about how list views and expandable list views work in Android. I am trying to incorporate this tutorial in my own project and I have run in to a problem. My ExpandListAdapter class reports an error unless I implement these methods:

public View getChildView(int groupPosition, int childPosition,
			boolean isLastChild, View convertView, ViewGroup parent) {				
		// TODO Auto-generated method stub
               return null;
	}

	public View getGroupView(int groupPosition, boolean isExpanded,
			View convertView, ViewGroup parent) {
		// TODO Auto-generated method stub
		return null;
		}


I am getting a null pointer exception on the line,
ExpandList.setAdapter(ExpAdapter);

and i believe that this it being caused by those two methods returning null. (I am new to java and android so I may be wrong)

Do you have any ideas on how I might work around that? Thank you.
Was This Post Helpful? 0
  • +
  • -

#11 EndLessMind  Icon User is offline

  • These are the droids you're looking for
  • member icon

Reputation: 194
  • View blog
  • Posts: 1,099
  • Joined: 13-March 09

Posted 01 August 2012 - 02:45 PM

Thanks :)

The getChildView should look like this
	public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View view,
			ViewGroup parent) {
		ExpandListChild child = (ExpandListChild) getChild(groupPosition, childPosition);
		if (view == null) {
			LayoutInflater infalInflater = (LayoutInflater) context.getSystemService(context.LAYOUT_INFLATER_SERVICE);
			view = infalInflater.inflate(R.layout.expandlist_child_item, null);
		}
		TextView tv = (TextView) view.findViewById(R.id.tvChild);
		tv.setText(child.getName().toString());
		tv.setTag(child.getTag());
		return view;
	}


and the getGroupView should look like this
	public View getGroupView(int groupPosition, boolean isLastChild, View view,
			ViewGroup parent) {
		ExpandListGroup group = (ExpandListGroup) getGroup(groupPosition);
		if (view == null) {
			LayoutInflater inf = (LayoutInflater) context.getSystemService(context.LAYOUT_INFLATER_SERVICE);
			view = inf.inflate(R.layout.expandlist_group_item, null);
		}
		TextView tv = (TextView) view.findViewById(R.id.tvGroup);
		tv.setText(group.getName());
		// TODO Auto-generated method stub
		return view;
	}

But the only if you are using the xml-layout for the group-item and child-item that's shown in the tutorial :)
About the NullPointerExeption, are you initializing the adaper?
adapter = new ExpandListAdapter(MainActivity.this, ExpListItems); 


Hope it helps :)
Was This Post Helpful? 1
  • +
  • -

#12 admin2000  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 09-May 09

Posted 02 August 2012 - 03:13 AM

Thanks for your tutorials,
how I can link children items to open HTML files (in asset folder).
Was This Post Helpful? 0
  • +
  • -

#13 EndLessMind  Icon User is offline

  • These are the droids you're looking for
  • member icon

Reputation: 194
  • View blog
  • Posts: 1,099
  • Joined: 13-March 09

Posted 02 August 2012 - 03:26 PM

Sure you can :)

Just use the OnChildClickListener() :)

private OnChildClickListener ExpandList_ItemClicked =  new OnChildClickListener() {

		public boolean onChildClick(ExpandableListView parent, View v,
				int groupPosition, int childPosition, long id) {
			// TODO Auto-generated method stub
			ExpandListChild ch =  ExpListItems.get(groupPosition).getItems().get(childPosition);
			//Your code where
			return false;
		}
		
	};



then use ExpandList.setOnChildClickListener(ExpandList_ItemClicked);
Was This Post Helpful? 0
  • +
  • -

#14 michaelholland5  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 06-August 12

Posted 06 August 2012 - 04:26 PM

View PostEndLessMind, on 02 August 2012 - 03:26 PM, said:

Sure you can :)

Just use the OnChildClickListener() :)

private OnChildClickListener ExpandList_ItemClicked =  new OnChildClickListener() {

		public boolean onChildClick(ExpandableListView parent, View v,
				int groupPosition, int childPosition, long id) {
			// TODO Auto-generated method stub
			ExpandListChild ch =  ExpListItems.get(groupPosition).getItems().get(childPosition);
			//Your code where
			return false;
		}
		
	};



then use ExpandList.setOnChildClickListener(ExpandList_ItemClicked);



This was great, but where does this bit of code go? I followed your example exactly and it is working but i'm just not sure where to add this final piece.

Sorry if its a stupid question, and thanks for all your help
Was This Post Helpful? 0
  • +
  • -

#15 EndLessMind  Icon User is offline

  • These are the droids you're looking for
  • member icon

Reputation: 194
  • View blog
  • Posts: 1,099
  • Joined: 13-March 09

Posted 07 August 2012 - 03:04 PM

The code in the code-tag is to be for it self, just like a void.
The code in the "inline"-section, is to be placed in the same part as where you set the adapter.
In this example, it's in the onCreate-method
Was This Post Helpful? 0
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2