One of the missing widgets from Android’s UI toolkit is the abilty to have a sortable list of items. For an example, look at organising a playlist within the Music app and moving songs around, a customised ListView is needed to achieve that functionality.

We will start with a normal list that shows the contents of the list’s items in a Toast dialog when an item is tapped.

I am making the assumption that you are developing for Android with Eclipse and already have the environment and emulators set up and ready to go.

The code for our base Activity, SortableListViewActivity, is:

package com.techrepublic.sortablelistview;import android.app.ListActivity; import android.os.Bundle;import android.view.View;import android.widget.ArrayAdapter;import android.widget.ListView;import android.widget.Toast;public class SortableListViewActivity extends ListActivity {private Object[] sArray  = {"Item 0", "Item 1", "Item 2", 42, false, "Item 5", "Item 6"};/** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);setContentView(R.layout.main); ArrayAdapter adp = new ArrayAdapter(this, R.layout.listrow, sArray);setListAdapter(adp);} @Override protected void onListItemClick(ListView l, View v, int position, long id) {String selection = sArray[position].toString();Toast.makeText(this, selection, Toast.LENGTH_SHOW).show();}} 

This is a simple list that takes an array of Objects, sArray, and presents them to the ListActivity via the ArrayAdapter. The onListItemClick function is called when one of the list items is tapped, and it shows the Toast.

The UI code for the list resides in /res/layout/ and is as follows for main.xml:

 android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" >  android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="wrap_content" > 

The id for the ListView must be “@android:id/list” for our ListActivity to work.

For listrow.xml it is:

android:id="@+id/title" android:layout_width="fill_parent" android:layout_height="80px" android:gravity="center_vertical" android:paddingLeft="6dip" 

Spark up the emulator and the code should show Toasts of list items.

Now that we have a list, let’s make it sortable by dragging.

Thanks to the permissiveness of Android’s licensing, we are able to make use of the same component that the Music app’s playlist uses. Navigate over to the github mirror of the Android source and grab a copy of the TouchInterceptor and drop it into the src folder. Make sure to correct the package name and comment out line 390 that sets a background resource that we don’t have, and then change line 126 to cast to a TextView as this is what our list contains:

TextView item = (TextView) getChildAt(itemnum - getFirstVisiblePosition());

To get R.dimen.normal_height and R.dimen.expanded_height to resolve on lines 84 and 86, we need to create a file called res/values/dimens.xml and make its contents:

80dp160dp

Return to the main.xml where we need to replace our ListView with the following TouchInterceptor:

android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" android:drawSelectorOnTop="false" android:fastScrollEnabled="true" android:textSize="18sp"

And add to the SortableListViewActivity:

private TouchInterceptor mList; private TouchInterceptor.DropListener mDropListener = new TouchInterceptor.DropListener() {public void drop(int from, int to) {System.out.println("Droplisten from:"+from+" to:"+to); //Assuming that item is moved up the list int direction = -1; int loop_start = from; int loop_end = to; //For instance where the item is dragged down the list  if(from < to) {direction = 1;} Object target = sArray[from]; for(int i=loop_start;i!=loop_end;i=i+direction){sArray[i] = sArray[i+direction];} sArray[to] = target; System.out.println("Changed array is:"+Arrays.toString(sArray)); ((BaseAdapter) mList.getAdapter()).notifyDataSetChanged();}}; 

I’ve left the debugging output in this version so you can see what is going on.

At the end of SortableListViewActivity’s onCreate method add:

mList = (TouchInterceptor) getListView(); mList.setDropListener(mDropListener); registerForContextMenu(mList); 

If you run the emulator again, it is now possible to drag the list items if you grab them on their far left-hand side. Functionality-wise, it is complete, but we need to make some aesthetic changes to make it usable.

Let’s move the handle for dragging the items onto the right-hand side. We can do that by changing line 132 in the TouchInterceptor to:

 if (item.getRight() - x < 20) {

A handle image is added by adding a background attribute to the TextView in listrow.xml:

android:background="@drawable/grablines"

Then we must create the grablines.xml file in /res/drawable and make its contents:

xmlns:android="http://schemas.android.com/apk/res/android" android:src="@drawable/handle" android:gravity="right" /> 

This file makes an image called handle stick to the right-hand side — the handle image I used is a 10×40 png file that is filled with a solid orange colour and stored in /res/drawable.

Now our handle is visible to the user so that they know where to grab.

Last little thing to do is to clean up listrow.xml by changing the layout_height to the one specified in our dimens file:

android:layout_height="@dimen/normal_height"

And let’s get a little transparency in there by adding an alpha parameter to the window manager parameters in the startDragging method within the TouchInterceptor:

mWindowParams.alpha = 0.5f;

Now you have a fully functional SortableListView to make your Android application that much more user-friendly and intuitive.