Section Headers for Android ListViews
When building the Android version of the iLike Concert app, I wanted to have day headers for the concert list.
This was easy on the iPhone; sections are built into the oUITableView class.
Surprisingly, the ListView class in Android doesn't provide any corresponding functionality, as of Android 2.1.
Jeff Sharkey's SeparatedListAdapter provides one way to get this functionality; it glues together a number of individual adapters for each section into an overall list.
In my case, I had one SimpleCursorAdapter for the whole list, so I didn't want to break it into individual adapters just to display sections.
Instead, I made the header a part of the list cell layout, and hid the header on the rows where I didn't want to display it. The headers look as follows:

My layout was like as follows; note the use of the explicit background color and textColorHighlight in the date header to prevent it from appearing as selected.
-
<?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="wrap_content"
-
android:orientation="vertical">
-
-
<TextView android:id="@+id/date_header"
-
android:textSize="20px"
-
android:textStyle="bold"
-
android:textColor="#000"
-
android:textColorHighlight="#000"
-
android:background="#DDD"
-
android:visibility="gone"
-
android:layout_width="fill_parent"
-
android:layout_height="wrap_content"/>
-
-
<LinearLayout
-
xmlns:android="http://schemas.android.com/apk/res/android"
-
android:layout_width="fill_parent"
-
android:layout_height="77px"
-
android:gravity="center_vertical"
-
android:orientation="horizontal">
-
-
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="100px" android:layout_height="75px" android:gravity="center_vertical|center_horizontal" android:orientation="horizontal">
-
<ImageView android:id="@+id/image" android:layout_width="75px" android:layout_height="75px"/>
-
</LinearLayout>
-
-
<LinearLayout
-
xmlns:android="http://schemas.android.com/apk/res/android"
-
android:layout_width="fill_parent"
-
android:layout_height="wrap_content"
-
android:gravity="center_vertical"
-
android:orientation="vertical">
-
-
<TextView android:id="@+id/title"
-
android:textSize="20px"
-
android:textStyle="bold"
-
android:layout_width="fill_parent"
-
android:layout_height="wrap_content"/>
-
<TextView android:id="@+id/description"
-
android:textSize="14px"
-
android:layout_width="fill_parent"
-
android:layout_height="wrap_content"/>
-
</LinearLayout>
-
</LinearLayout>
-
</LinearLayout>
The view binder assumes a function called isHeaderVisible to decide whether the header should be visible for the current row in the cursor; implement as appropriate for your application. (For example, our application displays a header whenever the date of the current row is different from the previous row.)
-
SimpleCursorAdapter listAdapter = new SimpleCursorAdapter(mContext,
-
R.layout.list_item,
-
mEventsCursor,
-
new int[] {R.id.image, R.id.title, R.id.description, R.id.date_header });
-
final int nDateIndex = mEventsCursor.getColumnIndex("event_date_string");
-
-
listAdapter.setViewBinder( new SimpleCursorAdapter.ViewBinder()
-
{
-
columnIndex)
-
{
-
if (columnIndex == nDateIndex) {
-
if (isHeaderVisible(cursor)) {
-
prevDate = dateString;
-
((TextView) view).setText(dateString);
-
} else {
-
((TextView) view).setText("");
-
}
-
return true;
-
}
-
return false;
-
}
-
});