Wednesday, December 16, 2009

Creating a ListView with Alternating Colors in Android

I've seen a lot of posts, and have done a lot of googling to figure out how to create a listview in Android with alternating colors. For example, row 1 light gray, row 2 dark gray, etc.

Here's a very easy way to accomplish this. It just involves creating a super-simple custom adapter.

Here's the source code/Eclipse project.

This example walks you through creating the project from scratch using eclipse and is valid for at least Android 1.5.

STEP 1) Create a new android project
- Give it a name and location
- Select Build Target of 1.5
- Give it a unique application name
- For this example, package name should be set to com.db.alternatinglistview
- Create activity is checked and name is MainActivity

STEP 2) Open up main.xml and modify it to have a listview as follows

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>

<ListView android:id="@android:id/list" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:visibility="visible"/>

</LinearLayout>



STEP 3) Open up MainActivity and have it extend ListActivity

public class MainActivity extends ListActivity {
...
}


STEP 4) Let's create a list of cars, so create a Car class:

public class Car {
public String make;
public String model;

public Car(String make, String model) {
this.make = make;
this.model = model;
}
}


STEP 5) Have your Car.java model class extend HashMap and override get(). This is required because the SimpleAdapter will map fields from your list of Cars to widget ids in the layout (this should make more sense in the steps following).

public class Car extends HashMap {
...
public static String KEY_MODEL = "model";
public static String KEY_MAKE = "make";
@Override
public String get(Object k) {
String key = (String) k;
if (KEY_MAKE.equals(key))
return make;
else if (KEY_MODEL.equals(key))
return model;
return null;
}
...
}


STEP 6) Create a new SimpleAdapter which extends SimpleAdapter and extends the getView() method. This will allow us to call super.getView() and then modify the view before it is returned:

public class CarListAdapter extends SimpleAdapter {

private List<Car> cars;
/*
* Alternating color list -- you could initialize this from anywhere.
* Note that the colors make use of the alpha here, otherwise they would be
* opaque and wouldn't give good results!
*/
private int[] colors = new int[] { 0x30ffffff, 0x30808080 };

@SuppressWarnings("unchecked")
public CarListAdapter(Context context,
List<? extends Map<String, String>> cars,
int resource,
String[] from,
int[] to) {
super(context, cars, resource, from, to);
this.cars = (List<Car>) cars;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);

int colorPos = position % colors.length;
view.setBackgroundColor(colors[colorPos]);
return view;
}

}


STEP 7) Lastly, in your MainActivity, instantiate the new custom list adapter and set it on your activity:

public class MainActivity extends ListActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

// Create our own version of the list adapter
List<Car> cars = getData();
ListAdapter adapter = new CarListAdapter(this, cars,
android.R.layout.simple_list_item_2, new String[] {
Car.KEY_MODEL, Car.KEY_MAKE }, new int[] {
android.R.id.text1, android.R.id.text2 });
this.setListAdapter(adapter);
}

private List<Car> getData() {
List<Car> cars = new ArrayList<Car>();
cars.add(new Car("Dodge", "Viper"));
cars.add(new Car("Chevrolet", "Corvette"));
cars.add(new Car("Aston Martin", "Vanquish"));
cars.add(new Car("Lamborghini", "Diablo"));
cars.add(new Car("Ford", "Pinto"));
return cars;
}
}


Here's an example using the above code:




STEP 8)) Run the app and see the results. Play with the colors & alpha to control the look-n-feel. For example, modifying the
int[] colors>
in CarListAdapter.java to the following:

private int[] colors = new int[] { 0x30ffffff, 0x30ff2020, 0x30808080 };


Yields the following results (goofy, but it makes the point!):