How do I build a ListView to display my custom class items?
One of the most common interface elements used in Android apps is the
ListView. This presents to the user a scrollable list of tappable items. The best place to start with this is and
Android Developers ListView Tutorial which will cover the basics of creating an
activity with the
ListView control and displaying a list of items from a string array.
In a real world app you will probably want to build a list with something other than a string array. Commonly you will have a collection of your own type of object, or you may want to display listview items with an icon. I will show you how to use a ListView to display these objects and also handle the tap event.
Let's start with the class object that will consist of a text label, a drawable for the icon and also an index value to track item selection:
CustomListItem.java
package com.example.advancedList;
import android.graphics.drawable.Drawable;
public class CustomListItem {
private int mIndex;
private String mLabel;
private Drawable mPicture;
public CustomListItem(final int index, final String label, final Drawable pic) {
mIndex = index;
mLabel = label;
mPicture = pic;
}
public int getIndex() {
return mIndex;
}
public String getLabel() {
return mLabel;
}
public Drawable getPicture() {
return mPicture;
}
}
Now that we have our class defined, let's create the layout that will be used to display the
individual list item, which is a simple
RelativeView with an
ImageView for the icon and a
TextView for the label:
Create
res/layout/list_item.xml :
<?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">
<TextView
android:id="@+id/txtLabel"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="List item" />
<ImageView
android:id="@+id/txtImgIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@null"
android:layout_toRightOf="@id/txtLabel" />
</RelativeLayout>
Hopefully so far everything has been quite straight forward. We now need to define a custom list adapter that extends the
BaseAdapter class, this will allow us to fully control the way the ListView is constructed.
Create a class named MyListItemAdapter.java:
package com.example.advancedList;
import java.util.List;
import android.content.Context;
import android.graphics.Bitmap;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
// Custom list item class for menu items
public class MyListItemAdapter extends BaseAdapter {
private List<CustomListItem> items;
private Context context;
private int numItems = 0;
public MyListItemAdapter(final List<CustomListItem> items, Context context) {
this.items = items;
this.context = context;
this.numItems = items.size();
}
public int getCount() {
return numItems;
}
public CustomListItem getItem(int position) {
return items.get(position);
}
public long getItemId(int position) {
return 0;
}
public View getView(int position, View convertView, ViewGroup parent) {
// Get the current list item
final CustomListItem item = items.get(position);
// Get the layout for the list item
final RelativeLayout itemLayout = (RelativeLayout) LayoutInflater.from(context).inflate(R.layout.list_item, parent, false);
// Set the icon as defined in our list item
ImageView imgIcon = (ImageView) itemLayout.findViewById(R.id.imgIcon);
imgIcon.setImageDrawable(item.getPicture());
// Set the text label as defined in our list item
TextView txtLabel = (TextView) itemLayout.findViewById(R.id.txtLabel);
txtLabel.setText(item.getLabel());
return itemLayout;
}
}
Next let's knock together a simple layout for the main activity. This will consist of a ListView for our items and a TextView that is displayed if the list is ever empty. Note here the use of special Android reserved IDs for the controls. This allows the list to be picked up for the ListActivity we'll use and also know to only display the TextView if there is no data in the ListView.
We'll call the file
res/layout/list_example.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_height="fill_parent"
android:layout_width="fill_parent">
<ListView
android:id="@id/android:list"
android:layout_height="wrap_content"
android:layout_width="fill_parent" />
<TextView
android:id="@id/android:empty"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Nothing to list" />
</LinearLayout>
We now need to build our main Activity which extends the ListActivity class using our layout defined previously. Within the activity's onCreate method we create a
List of our
CustomListItem type and add 3 new items to it. We then populate a new
ListAdapter using our
myListItemAdapter class and assign to it our list of items:
src/com.example.advancedList/Main.java :
package com.example.advancedList;
import java.util.ArrayList;
import java.util.List;
import android.app.ListActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.AdapterView.OnItemClickListener;
public class Main extends ListActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.list_example);
// Create list of items based upon class
final List<CustomListItem> items = new ArrayList<CustomListItem>(3);
items.add(new CustomListItem (1, "Item 1", getResources().getDrawable(R.drawable.icon)));
items.add(new CustomListItem (2, "Item 2", getResources().getDrawable(R.drawable.icon)));
items.add(new CustomListItem (3, "Item 3", getResources().getDrawable(R.drawable.icon)));
// Populate the list view
ListAdapter adapter = new myListItemAdapter(items, this);
ListView lv = getListView(); // Because we are extending ListActivity we cal this but could specify
lv.setAdapter(adapter);
lv.setTextFilterEnabled(true);
// Add listener for item clicks
lv.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// Retrieve our class object and use index to resolve item tapped
final MenuListItem item = items.get(position);
final int menuIndex = item.getIndex();
switch (menuIndex) {
case 1:
break;
case 2:
break;
case 3:
break;
default:
break;
}
}
});
}
}
You'll see that once we have our list adapter set up it is applied to the list view. We then assign a listener to the list view to pick up click events. Within this the first thing we do it obtain the item from the list that was clicked. We then have the freedom to make our code react to any aspect of our object.
I have used this approach several times and in fact have never displayed a list from a string array. I hope you find this guide useful.