Thursday, August 11, 2011

Android Expandable List View Tutorial

One of the features that I am including the COOK app is a list of items that are expandable.  This allows me to condense a lot of information into a smaller list.  The user can quickly scroll through the list to find their item, tap it and the item expands into a larger explanation of the item.  This tutorial will show you a simple process for creating an expandable list by showing you all of the java and xml necessary.

Preview


Step 1: Start a New Android Project
Click File>New>Android Project.  In the Project Name: field enter ExpandableList Project.  Select the latest API level you are comfortable with (API 10 for me).  In the Package Name: field enter com.androgue.explist.  In the Create Activity: field enter main(no caps) for the initial activity.  Click finish.

Step 2: Modify the strings.xml file
In the package explorer, browse to res/values/strings.xml.  Add the following code to the file.

    ExpList
	No items

Step 3: Add your Max/Min icons
Add the two icons below for your minimized and maximized states.

These icons signal the user that they have expanded an item in the list, similar to the plus - minus signs in the package explorer

Step 4: Create a expander_group.xml file to Flip the Icons
In the package explorer, right-click the drawable folder and click New>Android XML File.  At the bottom of the window select the root element "selector".  Name the file expander_group.  Then add the following code.

    
    

Step 5: Edit the main.xml File
In the layout folder, open the main.xml file and add the following code.

 
     
 
     


Step 6: Create the group_row.xml
Right-click on the layout folder and select New>Android XML File.  Name the file group_row.xml and click Finish.  Add the following code to the file.





Step 7: Create the child_row.xml
Do the same directions as in Step 6 and name the file child_row.xml.  Add the following code to the file.


    

    


Step 8: Build the first java file
In the src folder, right-click on the com.androgue.explist folder and then select New>Class.  Name the file SimpleExpandableListAdapterWithEmptyGroups.  Add the following code to the new java file.
package com.androgue.explist;

import java.util.List;
import java.util.Map;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.SimpleExpandableListAdapter;

public class SimpleExpandableListAdapterWithEmptyGroups extends
		SimpleExpandableListAdapter {

	private static final int[] EMPTY_STATE_SET = {};
    private static final int[] GROUP_EXPANDED_STATE_SET =
            {android.R.attr.state_expanded};
    private static final int[][] GROUP_STATE_SETS = {
         EMPTY_STATE_SET, // 0
         GROUP_EXPANDED_STATE_SET // 1
	};

	public SimpleExpandableListAdapterWithEmptyGroups(Context context,
			List> groupData, int groupLayout,
			String[] groupFrom, int[] groupTo,
			List>> childData,
			int childLayout, String[] childFrom, int[] childTo) {
		super(context, groupData, groupLayout, groupFrom, groupTo, childData,
				childLayout, childFrom, childTo);
	}

	public SimpleExpandableListAdapterWithEmptyGroups(Context context,
			List> groupData, int expandedGroupLayout,
			int collapsedGroupLayout, String[] groupFrom, int[] groupTo,
			List>> childData,
			int childLayout, String[] childFrom, int[] childTo) {
		super(context, groupData, expandedGroupLayout, collapsedGroupLayout,
				groupFrom, groupTo, childData, childLayout, childFrom, childTo);
	}

	public SimpleExpandableListAdapterWithEmptyGroups(Context context,
			List> groupData, int expandedGroupLayout,
			int collapsedGroupLayout, String[] groupFrom, int[] groupTo,
			List>> childData,
			int childLayout, int lastChildLayout, String[] childFrom,
			int[] childTo) {
		super(context, groupData, expandedGroupLayout, collapsedGroupLayout,
				groupFrom, groupTo, childData, childLayout, lastChildLayout,
				childFrom, childTo);
	}

	public View getGroupView (int groupPosition, 
			boolean isExpanded, 
			View convertView, 
			ViewGroup parent) {
		View v = super.getGroupView( groupPosition, isExpanded, convertView, parent);
		View ind = v.findViewById( R.id.explist_indicator);
		if( ind != null ) {
			ImageView indicator = (ImageView)ind;
			if( getChildrenCount( groupPosition ) == 0 ) {
				indicator.setVisibility( View.INVISIBLE );
			} else {
				indicator.setVisibility( View.VISIBLE );
				int stateSetIndex = ( isExpanded ? 1 : 0) ;
				Drawable drawable = indicator.getDrawable();
				drawable.setState(GROUP_STATE_SETS[stateSetIndex]);
			}
		}
		return v;
	}

	private void dumpViewGroup( View v ) {
		if( v instanceof ViewGroup ) {
			ViewGroup vg = (ViewGroup)v;
			for( int i = 0 ; i < vg.getChildCount() ; ++i ) {
				View child = vg.getChildAt( i );
				Log.d( LOG_TAG, "dumpViewGroup: child["+i+"]: "+child );
			}
		} else
			Log.d(LOG_TAG, "dumpViewGroup: "+v+" is not a ViewGroup");
	}
	
	private static final String LOG_TAG = "EmptyGroupsAdapter";
}
Step 9: Build the last java file In the src folder, open the main.java file.  Add the following code.
package com.androgue.explist;

import android.app.ExpandableListActivity;
import android.os.Bundle;
import java.util.List;
import java.util.ArrayList;
import java.util.HashMap;

public class main extends ExpandableListActivity
{
    static final String colors[] = {
	  "grey",
	  "blue",
	  "yellow",
	  "red"
	};

	static final String shades[][] = {
// Shades of grey
	  {
		"lightgrey","#D3D3D3",
		"dimgray","#696969",
		"sgi gray 92","#EAEAEA"
	  },
// Shades of blue
	  {
		"dodgerblue 2","#1C86EE",
		"steelblue 2","#5CACEE",
		"powderblue","#B0E0E6"
	  },
	  {},
	  {}
    };

    @Override
    public void onCreate(Bundle icicle)
    {
        super.onCreate(icicle);
        setContentView(R.layout.main);
        SimpleExpandableListAdapterWithEmptyGroups expListAdapter =
			new SimpleExpandableListAdapterWithEmptyGroups(
				this,
				createGroupList(),	
				R.layout.group_row,	
				new String[] { "colorName" },	
				new int[] { R.id.groupname },		
				createChildList(),	
				R.layout.child_row,	
				new String[] { "shadeName", "rgb" },	
				new int[] { R.id.childname, R.id.rgb }	
			);
		setListAdapter( expListAdapter );
    }

	private List createGroupList() {
	  ArrayList result = new ArrayList();
	  for( int i = 0 ; i < colors.length ; ++i ) {
		HashMap m = new HashMap();
	    m.put( "colorName",colors[i] );
		result.add( m );
	  }
	  return (List)result;
    }

  private List createChildList() {
	ArrayList result = new ArrayList();
	for( int i = 0 ; i < shades.length ; ++i ) {
	  ArrayList secList = new ArrayList();
	  for( int n = 0 ; n < shades[i].length ; n += 2 ) {
	    HashMap child = new HashMap();
		child.put( "shadeName", shades[i][n] );
	    child.put( "rgb", shades[i][n+1] );
		secList.add( child );
	  }
	  result.add( secList );
	}
	return result;
  }

}
Step 10: Run your App
Your app is now complete.  Start your favorite emulator and run the app.


Download the Source Code
com.androgue.explist (.zip, 56k)

5 comments:

  1. What IDE are you using? Your generics will not compile on eclipse..

    ReplyDelete
    Replies
    1. Eclipse is not a compiler

      Delete
    2. Thats the reason the word is mentioned. Take a hint.

      Delete
  2. This is not the best tutorial to follow. Your selectors are wrong and there are other mistakes too.

    Please review your code or unshare it.

    ReplyDelete
  3. well explained man..Thanks a lot!

    ReplyDelete