Separating Lists with Headers in Android 0.9 PDF Print E-mail

Earlier today the latest Android 0.9 SDK was released, and it’s packed full of wonderful changes. As you play around, you might see ListViews split into sections using separating headers. (Example shown on the right is the browser settings list.)

There isn’t an easy way of creating these separated lists, so I’ve put together SeparatedListAdapter which does it quickly. To summarize, we’re creating a new BaseAdapter that can contain several other Adapters, each with their own section headers.

First let’s create some simple XML layouts to be used for our lists: first the header view, then two item views that we’ll use later for the individual lists. (Thanks to Romain Guy for helping me find existing styles to keep these XML layouts nice and tidy.)

 
  1. <!-- list_header.xml -->  
  2. <TextView  
  3.     xmlns:android="http://schemas.android.com/apk/res/android"  
  4.     android:id="@+id/list_header_title"  
  5.     android:layout_width="fill_parent"  
  6.     android:layout_height="wrap_content"  
  7.     android:paddingTop="2dip"  
  8.     android:paddingBottom="2dip"  
  9.     android:paddingLeft="5dip"  
  10.     style="?android:attr/listSeparatorTextViewStyle" />  
  11.   
  12. <!-- list_item.xml -->  
  13. <TextView  
  14.     xmlns:android="http://schemas.android.com/apk/res/android"  
  15.     android:id="@+id/list_item_title"  
  16.     android:layout_width="fill_parent"  
  17.     android:layout_height="fill_parent"  
  18.     android:paddingTop="10dip"  
  19.     android:paddingBottom="10dip"  
  20.     android:paddingLeft="15dip"  
  21.     android:textAppearance="?android:attr/textAppearanceLarge"  
  22.     />  
  23.   
  24. <!-- list_complex.xml -->  
  25. <LinearLayout  
  26.     xmlns:android="http://schemas.android.com/apk/res/android"  
  27.     android:layout_width="fill_parent"  
  28.     android:layout_height="wrap_content"  
  29.     android:orientation="vertical"  
  30.     android:paddingTop="10dip"  
  31.     android:paddingBottom="10dip"  
  32.     android:paddingLeft="15dip"  
  33.     >  
  34.     <TextView  
  35.         android:id="@+id/list_complex_title"  
  36.         android:layout_width="fill_parent"  
  37.         android:layout_height="wrap_content"  
  38.         android:textAppearance="?android:attr/textAppearanceLarge"  
  39.         />  
  40.     <TextView  
  41.         android:id="@+id/list_complex_caption"  
  42.         android:layout_width="fill_parent"  
  43.         android:layout_height="wrap_content"  
  44.         android:textAppearance="?android:attr/textAppearanceSmall"  
  45.         />  
  46. </LinearLayout>  

Now let’s create the actual SeparatedListAdapter class which provides a single interface to multiple sections of other Adapters. After using addSection() to construct the child sections, you can easily use ListView.setAdapter() to present the now-separated list to users.

As for the Adapter internals, to correctly find the selected item among the child Adapters, we walk through subtracting from the original position until we find either a header (position = 0) or item in the current child Adapter (position < size).

Here’s the source for SeparatedListAdapter:

 
  1. public class SeparatedListAdapter extends BaseAdapter {  
  2.   
  3.     public final Map<String,Adapter> sections = new LinkedHashMap<String,Adapter>();  
  4.     public final ArrayAdapter<String> headers;  
  5.     public final static int TYPE_SECTION_HEADER = 0;  
  6.   
  7.     public SeparatedListAdapter(Context context) {  
  8.         headers = new ArrayAdapter<String>(context, R.layout.list_header);  
  9.     }  
  10.   
  11.     public void addSection(String section, Adapter adapter) {  
  12.         this.headers.add(section);  
  13.         this.sections.put(section, adapter);  
  14.     }  
  15.   
  16.     public Object getItem(int position) {  
  17.         for(Object section : this.sections.keySet()) {  
  18.             Adapter adapter = sections.get(section);  
  19.             int size = adapter.getCount() + 1;  
  20.   
  21.             // check if position inside this section  
  22.             if(position == 0return section;  
  23.             if(position < size) return adapter.getItem(position - 1);  
  24.   
  25.             // otherwise jump into next section  
  26.             position -= size;  
  27.         }  
  28.         return null;  
  29.     }  
  30.   
  31.     public int getCount() {  
  32.         // total together all sections, plus one for each section header  
  33.         int total = 0;  
  34.         for(Adapter adapter : this.sections.values())  
  35.             total += adapter.getCount() + 1;  
  36.         return total;  
  37.     }  
  38.   
  39.     public int getViewTypeCount() {  
  40.         // assume that headers count as one, then total all sections  
  41.         int total = 1;  
  42.         for(Adapter adapter : this.sections.values())  
  43.             total += adapter.getViewTypeCount();  
  44.         return total;  
  45.     }  
  46.   
  47.     public int getItemViewType(int position) {  
  48.         int type = 1;  
  49.         for(Object section : this.sections.keySet()) {  
  50.             Adapter adapter = sections.get(section);  
  51.             int size = adapter.getCount() + 1;  
  52.   
  53.             // check if position inside this section  
  54.             if(position == 0return TYPE_SECTION_HEADER;  
  55.             if(position < size) return type + adapter.getItemViewType(position - 1);  
  56.   
  57.             // otherwise jump into next section  
  58.             position -= size;  
  59.             type += adapter.getViewTypeCount();  
  60.         }  
  61.         return -1;  
  62.     }  
  63.   
  64.     public boolean areAllItemsSelectable() {  
  65.         return false;  
  66.     }  
  67.   
  68.     public boolean isEnabled(int position) {  
  69.         return (getItemViewType(position) != TYPE_SECTION_HEADER);  
  70.     }  
  71.   
  72.     @Override  
  73.     public View getView(int position, View convertView, ViewGroup parent) {  
  74.         int sectionnum = 0;  
  75.         for(Object section : this.sections.keySet()) {  
  76.             Adapter adapter = sections.get(section);  
  77.             int size = adapter.getCount() + 1;  
  78.   
  79.             // check if position inside this section  
  80.             if(position == 0return headers.getView(sectionnum, convertView, parent);  
  81.             if(position < size) return adapter.getView(position - 1, convertView, parent);  
  82.   
  83.             // otherwise jump into next section  
  84.             position -= size;  
  85.             sectionnum++;  
  86.         }  
  87.         return null;  
  88.     }  
  89.   
  90.     @Override  
  91.     public long getItemId(int position) {  
  92.         return position;  
  93.     }  
  94.   
  95. }  

As expected, it correctly prevents the section headers from being selected, and seamlessly stiches together the various Adapters.

This approach also uses convertView correctly as long as the child Adapters return getItemViewType() and getViewTypeCount() normally. No special changes are needed for an Adapter to become a child.

Now let’s use SeparatedListAdapter in some example code. We use the XML layouts defined earlier to create an ArrayAdapter and an advanced two-row SimpleAdapter, and then add both as sections to our SeparatedListAdapter.

 
  1. public class ListSample extends Activity {  
  2.   
  3.     public final static String ITEM_TITLE = "title";  
  4.     public final static String ITEM_CAPTION = "caption";  
  5.   
  6.     public Map<String,?> createItem(String title, String caption) {  
  7.         Map<String,String> item = new HashMap<String,String>();  
  8.         item.put(ITEM_TITLE, title);  
  9.         item.put(ITEM_CAPTION, caption);  
  10.         return item;  
  11.     }  
  12.   
  13.     @Override  
  14.     public void onCreate(Bundle icicle) {  
  15.         super.onCreate(icicle);  
  16.   
  17.         List<Map<String,?>> security = new LinkedList<Map<String,?>>();  
  18.         security.add(createItem("Remember passwords""Save usernames and passwords for Web sites"));  
  19.         security.add(createItem("Clear passwords""Save usernames and passwords for Web sites"));  
  20.         security.add(createItem("Show security warnings""Show warning if there is a problem with a site's security"));  
  21.   
  22.         // create our list and custom adapter  
  23.         SeparatedListAdapter adapter = new SeparatedListAdapter(this);  
  24.         adapter.addSection("Array test"new ArrayAdapter<String>(this,  
  25.             R.layout.list_item, new String[] { "First item""Item two" }));  
  26.         adapter.addSection("Security"new SimpleAdapter(this, security, R.layout.list_complex,  
  27.             new String[] { ITEM_TITLE, ITEM_CAPTION }, new int[] { R.id.list_complex_title, R.id.list_complex_caption }));  
  28.   
  29.         ListView list = new ListView(this);  
  30.         list.setAdapter(adapter);  
  31.         this.setContentView(list);  
  32.   
  33.     }  
  34.   
  35. }  

The resulting interface behaves just like the browser preferences list, and you could easily create other custom Adapters to insert into the various sections, such as including icons or checkboxes.

These section headers can really help separate out otherwise-cluttered activities. I used them several places in my CompareEverywhere application which lets you easily compare prices and read reviews for any product with a barcode.

 

Source: http://www.jsharkey.org/blog/2008/08/18/separating-lists-with-headers-in-android-09/

Comments (13)Add Comment
thank you
written by Lane Alexander Tap Dancing , May 28, 2010

Lane Alexander Tap Dancing Thanks for the share. Just keep on sharing
report abuse
vote down
vote up
Votes: +0
birkenstock shoes
written by birkenstock , May 29, 2010
When you are on a holiday in some seaside resort where you will hike and walk on cliffs, Birckenstock is one of the brands to which you turn your attention to find some slippers or flip-flops that make a holiday in comfort and without pain in the feet after a romantic walk on the rocks.Birkenstocks is the well-known German footwear brand: Birkenstock shoes, Birkenstock sandals and Birkenstock clogs.Birkenstock Gizeh is a flattering flip-flop style with a leather upper that will look great with shorts, jeans or dresses, at the same time, it has an irresistible air between the tourist and hiking, and you can be sure that the evening will have no pain, given the high quality these shoes.
report abuse
vote down
vote up
Votes: +0
...
written by jordan shoes , May 31, 2010
would a little more money make us a little happier? Many of us smirk and nod. There is, we believe, some connection between fiscal fitness and feeling fantasti air jordan shoes
. Most of us would say that, yes, we would like to DC. michael jordan shoes
Three in four American collegians now consider it.
report abuse
vote down
vote up
Votes: +0
air max 2009
written by air max 2009 , May 31, 2010
are you looking for a air max 2009?
here are not only offer the nike free shoes ,but aslo for thenew lebron VII shoes
report abuse
vote down
vote up
Votes: +0
...
written by mbt , June 18, 2010
contests administered by SUN, ACM, and IBM. He also had co-authored U.S.
report abuse
vote down
vote up
Votes: +0
...
written by coach purses , June 19, 2010
then two item views that we’ll use later for the individual lists. (Thanks to Romain Guy for helping me find existing styles to keep these XML layouts nice and tidy.)
report abuse
vote down
vote up
Votes: +0
Cheap San Francisco 49ers Jerseys
written by sexy bikinis , June 24, 2010
It is not the NFL Jerseys critic who counts,not the man who points out how the strong man stumbles,the doer of deeds could have sexy bikinis sale done them better. The credit belongs to the man who is actually in the cheap nfl jerseys arens,whose face is marred by dust and sweat and blood;who stives Ed Hardy Bikini valiantly;who errs,and comes short again and again;because there is not effort without Ralph Lauren Bikini error and shortcoming;but who does actually strive to do the Cheap San Francisco 49ers Jerseys deeds;who knows the great San Francisco 49ers Jerseys Sale enthusiasms,the great devotions;who spends himself in a worthy cause,who at the best sexy bikinis knows in the end the triumphs of high achievement and who at the NFL Dallas Cowboys Jerseys worst,if he fails,at least fails whiledaring greatly,so that his place shall never be with those cold and timid souls who know neither victory nor defeat. We encourage our Cheap Kobe Bryant Jerseys children to be competitive, to get ahead, to make money, to acquire possession. In games and in business alike, the aim is to win the game, the trophy, the contract. We go in for Sexy Ed Hardy Bikini laboursaving devices, gadgets, speed and shortcuts. We think every young couple should set up a home of their own.
report abuse
vote down
vote up
Votes: +0
mbt
written by mbt shoes , June 29, 2010
Thanks to Romain Guy for helping me find existing styles to keep these XML layouts nice and tidy.)

ugg boots
report abuse
vote down
vote up
Votes: +0
shopping
written by fashion , July 06, 2010
the sun Gucci handbagstarts shining.
plants start growing.
flowers Y-3 shoestartopening.
birds start singing
And making Prada handbagtheir nests.
spring is here.
the hot Vibram rock shoesun'shining.
we start having fun.
we start Nike Air max shoesswimming.
we start eating ice cream.
the holidaysArmani are coming.
summer is here.
the wind Gucci shoesstarts blowing.
kites start flying.
leaves start Alife shoefalling.
we start having barbecues.
the holidays LV T-shirt menare ending.
autumn is here.
the snow Chanl shoestarts falling.
animals start sleeping.
dark days Armani jeansare coming.
the temperature's dropping.
we startBurberry shoe shivering.
winter is here.
report abuse
vote down
vote up
Votes: +0
go
written by fashion , July 06, 2010
www.ck-style513.com/HANDBAGS/G...dex_1.html
report abuse
vote down
vote up
Votes: +0
christian louboutin shoes
written by sexy lady shoes , July 08, 2010
Today so hot that I want to drink cool water.
christian louboutin boots
louboutin
report abuse
vote down
vote up
Votes: +0
Separating Lists with Headers in Android 0.9
written by learn to tap dance , July 21, 2010
I think it is really good idea to provide source for SeparatedListAdapter. Thanks!
report abuse
vote down
vote up
Votes: +0
...
written by nfl jerseys , July 27, 2010
christian louboutin shoes
ghd hair straighteners uk
report abuse
vote down
vote up
Votes: +0

Write comment
quote
bold
italicize
underline
strike
url
image
quote
quote
smile
wink
laugh
grin
angry
sad
shocked
cool
tongue
kiss
cry
smaller | bigger

security code
Write the displayed characters


busy
 

 

This domain is for sale! Please contact me via contact page!