While developing on the Android this week, I wanted to use a ListActivity. I used the ListActivity class quite a lot before, but this time I wanted to do something different with it. Instead of having a plain list, I wanted to have arrows on the right side of each list item, kind of like how the
iOS UITableView has it. I made several attempts of doing this and I was finally able to come up with a good solution.
The trick is to build your own list adapter (derived from the BaseAdapter), define an xml layout for each row in the list, and use the list adapter to populate the list with the layout that you defined. To start, we define some local variables from our CustomListAdapter class and write the constructor to cache some local variables:
public class CustomListAdapter extends BaseAdapter {
private String[] mListItemTxt = null;
private LayoutInflater mLayoutInflater = null;
private int mTextWidth = 0;
private int mTextHeight = 60; // in dip
// holder struct for each row
public static class CustomHolder {
public TextView text;
public ImageView image;
}
public CustomListAdapter(Context context, String[] listItemTxt, int textWidth) {
// cache data locally
mListItemTxt = listItemTxt;
mLayoutInflater =
(LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mTextWidth = textWidth;
}
...more code...
In my case, I chose to cache two things: a String array mListItemTxt, which holds the text for each row in the ListActivity, and an int mTextWidth, which is the width that the text in each row can occupy. We can calculate this width by getting the width of the arrow we have in our resources folder, and subtracting that value from the width of the display. Next we have to define the layout for each row of our ListActivity.
In our row layout, we have the following:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:orientation="vertical" android:id="@+id/relativeLayout1">
<TextView android:id="@+id/custom_list_item_txt"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="" android:textSize="24dip" android:layout_weight="1"
android:gravity="center|left"></TextView>
<ImageView android:id="@+id/custom_list_item_image"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:src="@drawable/icon" android:layout_toRightOf="@+id/custom_list_item_txt"
android:layout_weight="0"></ImageView>
</RelativeLayout>
After this, we need to complete the CustomListAdapter class:
@Override
public int getCount() {
// return 0 if null
return (mListItemTxt == null ? 0 : mListItemTxt.length);
}
@Override
public Object getItem(int position) {
return position;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
CustomHolder ch = null;
if(v == null) {
// create a new one if it doesnt exist
v = mLayoutInflater.inflate(R.layout.list_item, null);
ch = new CustomHolder();
ch.text = (TextView) v.findViewById(R.id.custom_list_item_txt);
ch.image = (ImageView) v.findViewById(R.id.custom_list_item_image);
v.setTag(ch);
}
else {
ch = (CustomHolder) v.getTag();
}
try {
// load the text and the arrow image
// also set width and height to make it look nice
ch.text.setText(mListItemTxt[position]);
ch.text.setWidth(mTextWidth);
ch.text.setHeight(mTextHeight);
ch.image.setTag(Integer.toString(position));
ch.image.setImageResource(R.drawable.arrow);
ch.image.setMinimumHeight(mTextHeight);
return v;
}
catch(Exception e) {
e.printStackTrace();
return null;
}
}
After defining these functions, add an
arrow icon to the resources folder and the list adapter should be ready to use. Check out the
source code, and screenshot: