Building a Custom Multi-Line ListView in Android

This tutorial will walk you through building a custom multi-line ListView in Android.

We’ll achieve this by extending BaseAdapter (or concrete ArrayAdapter) to turn a collection of objects into individual ListView items.

First, let’s define the layout for our scrollable ListView by placing the following in main.xml:

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

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="center_vertical|center_horizontal"
        android:text="Custom ListView Example" />

    <ListView
        android:id="@+id/srListView"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />

</LinearLayout>

Next, let’s define a layout for individual ListView items. Paste this layout code in a new layout file called custom_row_view.xml:

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

    <TextView
        android:id="@+id/name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#C20000"
        android:textSize="14sp"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/cityState"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/phone"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

Next, let’s create a POJO called SearchResults.java to represent contact search results. Paste this boilerplate code into it:

package com.publicstaticdroidmain.android;

public class SearchResults {
	 private String name = "";
	 private String cityState = "";
	 private String phone = "";

	 public void setName(String name) {
	  this.name = name;
	 }

	 public String getName() {
	  return name;
	 }

	 public void setCityState(String cityState) {
	  this.cityState = cityState;
	 }

	 public String getCityState() {
	  return cityState;
	 }
	 public void setPhone(String phone) {
	  this.phone = phone;
	 }

	 public String getPhone() {
	  return phone;
	 }
}

Now we need to build an Adapter. The Adapter will turn our collection of SearchResults into individual ListView items. Create a file called MyCustomBaseAdapter.java with these contents:

package com.publicstaticdroidmain.android;

import java.util.ArrayList;

import com.publicstaticdroidmain.R;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

public class MyCustomBaseAdapter extends BaseAdapter {
	private static ArrayList<SearchResults> searchArrayList;

	private LayoutInflater mInflater;

	public MyCustomBaseAdapter(Context context, ArrayList<SearchResults> results) {
		searchArrayList = results;
		mInflater = LayoutInflater.from(context);
	}

	public int getCount() {
		return searchArrayList.size();
	}

	public Object getItem(int position) {
		return searchArrayList.get(position);
	}

	public long getItemId(int position) {
		return position;
	}

	public View getView(int position, View convertView, ViewGroup parent) {
		ViewHolder holder;
		if (convertView == null) {
			convertView = mInflater.inflate(R.layout.custom_row_view, null);
			holder = new ViewHolder();
			holder.txtName = (TextView) convertView.findViewById(R.id.name);
			holder.txtCityState = (TextView) convertView
					.findViewById(R.id.cityState);
			holder.txtPhone = (TextView) convertView.findViewById(R.id.phone);

			convertView.setTag(holder);
		} else {
			holder = (ViewHolder) convertView.getTag();
		}

		holder.txtName.setText(searchArrayList.get(position).getName());
		holder.txtCityState.setText(searchArrayList.get(position)
				.getCityState());
		holder.txtPhone.setText(searchArrayList.get(position).getPhone());

		return convertView;
	}

	static class ViewHolder {
		TextView txtName;
		TextView txtCityState;
		TextView txtPhone;
	}
}

And finally, let’s update our main Activity class (mine is called CustomListViewActivity) to tie everything together:

package com.publicstaticdroidmain.android;

import java.util.ArrayList;

import com.publicstaticdroidmain.R;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.Toast;

public class CustomListViewActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        ArrayList<SearchResults> searchResults = GetSearchResults();
        
        final ListView lv = (ListView) findViewById(R.id.srListView);
        lv.setAdapter(new MyCustomBaseAdapter(this, searchResults));
        
        
        lv.setOnItemClickListener(new OnItemClickListener() {
			@Override
			public void onItemClick(AdapterView<?> a, View v, int position, long id) {
				Object o = lv.getItemAtPosition(position);
		        SearchResults fullObject = (SearchResults)o;
		        Toast.makeText(CustomListViewActivity.this, "You have chosen: " + " " + fullObject.getName(), Toast.LENGTH_LONG).show();
			}  
        });
    }
    
    private ArrayList<SearchResults> GetSearchResults(){
     ArrayList<SearchResults> results = new ArrayList<SearchResults>();
     
     SearchResults sr = new SearchResults();
     sr.setName("Justin Schultz");
     sr.setCityState("San Francisco, CA");
     sr.setPhone("415-555-1234");
     results.add(sr);
     
     sr = new SearchResults();
     sr.setName("Jane Doe");
     sr.setCityState("Las Vegas, NV");
     sr.setPhone("702-555-1234");
     results.add(sr);
     
     sr = new SearchResults();
     sr.setName("Lauren Sherman");
     sr.setCityState("San Francisco, CA");
     sr.setPhone("415-555-1234");
     results.add(sr);
     
     sr = new SearchResults();
     sr.setName("Fred Jones");
     sr.setCityState("Minneapolis, MN");
     sr.setPhone("612-555-8214");
     results.add(sr);
     
     sr = new SearchResults();
     sr.setName("Bill Withers");
     sr.setCityState("Los Angeles, CA");
     sr.setPhone("424-555-8214");
     results.add(sr);
     
     sr = new SearchResults();
     sr.setName("Donald Fagen");
     sr.setCityState("Los Angeles, CA");
     sr.setPhone("424-555-1234");
     results.add(sr);
     
     sr = new SearchResults();
     sr.setName("Steve Rude");
     sr.setCityState("Oakland, CA");
     sr.setPhone("515-555-2222");
     results.add(sr);
     
     sr = new SearchResults();
     sr.setName("Roland Bloom");
     sr.setCityState("Chelmsford, MA");
     sr.setPhone("978-555-1111");
     results.add(sr);

     sr = new SearchResults();
     sr.setName("Sandy Baguskas");
     sr.setCityState("Chelmsford, MA");
     sr.setPhone("978-555-2222");
     results.add(sr);
     
     sr = new SearchResults();
     sr.setName("Scott Taylor");
     sr.setCityState("Austin, TX");
     sr.setPhone("512-555-2222");
     results.add(sr);
     
     return results;
    }
}

And that’s it. If you’ve done everything correctly, you should wind up with this:

Android Custom Multi-Line ListView Screenshot

Android Custom Multi-Line ListView Screenshot

Here’s the zipped source code.


About this entry