Tuesday, May 24, 2011

Pinned Header ListView as in the Contacts app

The standard Android Contacts application has this PinnedHeaderListView implementation. This renders a letter (A, B, C, ...) in a section header on your ListView for all the list items starting with that letter. What's nice is that this section header stays visible as long as there is a list item visible starting with that letter. And it's being pushed up when the last list item is becoming invisible while scrolling the list view.

A sample project with the pinned header list view can be found at http://code.google.com/p/android-playground. Another example project using this list view is Devoxx 2010 Schedule app.


Layout definitions

First we need to define the layout definitions. We are not using a default ListView, but the custom PinnedHeaderListView.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <view class="net.peterkuterna.android.apps.pinnedheader.PinnedHeaderListView"
        android:id="@android:id/list"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

The layout for the header is also specified in a separated layout. An instance of this view will be passed on to the PinnedHeaderListView when setting up the list view.

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/header_text"
    android:layout_width="match_parent"
    android:layout_height="25dip"
    android:textStyle="bold"
    android:background="@color/pinned_header_background"
    android:textColor="@color/pinned_header_text"
    android:textSize="14sp"
    android:paddingLeft="6dip"
    android:gravity="center_vertical" />

Next, we also need to include this header view in the layout that defines the list item.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/list_item"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">
    <include layout="@layout/list_item_header" />
    <include layout="@android:layout/simple_list_item_1" />
    <View android:id="@+id/list_divider"
        android:layout_width="match_parent"
        android:layout_height="1px"
        android:background="@android:drawable/divider_horizontal_dark" />
</LinearLayout>

Setting up the PinnedHeaderListView

To actually use this PinnedHeaderListView you only need to provide it a suitable ListAdapter, the header View and an OnScrollListener.

private void setupListView() {
    PinnedHeaderListView listView = (PinnedHeaderListView) findViewById(android.R.id.list);
    listView.setPinnedHeaderView(LayoutInflater.from(this).inflate(R.layout.list_item_header, listView, false));
    listView.setOnScrollListener(mAdapter);
    listView.setDividerHeight(0);
}

Implementing the ListAdapter

The ListAdapter that you will pass on to the PinnedHeaderListView needs to have the following interfaces implemented:
  • PinnedHeaderAdapter
  • SectionIndexer
  • OnScrollListener

The PinnedHeaderAdapter interface defines two methods that need to be implemented. The method getPinnedHeaderState needs to return the state of the pinned header in your list view for a certain position. This allows the list view to identify if the header is gone, is visible or if it needs to be pushed up. The second method configurePinnedHeader is being called when your list view is being layout and allows you to adapt (text, colors, ...) the pinned header view.

A SectionIndexer is being used to easily identify a section for a given position and a position for a given section in the list view. These methods are being used when binding the pinned header, when detecting the pinned header state and when configuring the pinned header.

As last a OnScrollListener callback is implemented which will be called when the list has been scrolled and which will call on its turn the configureHeaderView method of the PinnedHeaderListView.

Thursday, May 19, 2011

Experience the ADT 11 tools

So you watched (or if you were lucky attended) the Google I/O session on Android Development Tools by Xavier Ducrohet and Tor Norbye, but you can't wait to try out some of this stuff? No problem at all! As stated on the Android Tools Project Site, the tools are developed entirely in the open and you can also contribute code if you want. All the steps to build the SDK and Eclipse-based tools are outlined in the Build Overview and Building the Eclipse-Based Tools pages.

But if you only want to test-drive the ADT Plugin for Eclipse, you can follow the next steps to have these build under OS X with Snow Leopard. One thing to note is that you need to have a case-sensitive file system on your Mac somewhere on which you install the Android sources. If you want to avoid partitioning your drive you can follow these guidelines to create a case-sensitive disk image. After you have followed the complete guidelines to initialize a build environment, you can go ahead and download the sources:

mkdir android
cd android
repo init -u git://android.git.kernel.org/platform/manifest.git
repo sync

Now that you have the Android sources, you can actually build the SDK:

. build/envsetup.sh
lunch sdk-eng
make -j3 sdk

In order to actually build the ADT Plugin for Eclipse, you need to download and install a version of Eclipse RCP 3.5.2. By default you can only build the tools on Linux, but building on a Mac is not a problem. To fix this, all you need to do is put the check-run-on-linux lines in comment in the files sdk/eclipse/scripts/build_server.sh and sdk/eclipse/scripts/build_plugins.sh. To actually build the plugins, perform the following:

export ECLIPSE_HOME=<location of Eclipse RCP 3.5.2>
cd sdk/eclipse/scripts
./build_server.sh <output directory of plugins>

Using this ADT plugin in Eclipse is now just a matter of adding this ADT archive as an update site when installing new software plugins in your Eclipse.

Want to know what has changed? Check out the Recent Changes page, but you can also find more info in the changes.txt file in the AOSP.

UPDATE: An official ADT 11 Release candidate has been made available which can be downloaded here.