Android ListView with Custom Layout and Filter example

How to display a List by inflating a Custom Layout in a ListView and filter the results from an EditText

Well if you familiar with using the ListView to display a simple list from an Array and looking to enhance the display with a custom layout then here is an example which will covers most of your needs. In this example we cover the follwing topics
  • Display data in a List using the ListView
  • Define a custom Layout based on your display needs
  • Ability to filter the results as you type in an EditText by extending the Filter class
  • Attach an OnItemClickListener to check when the user taps on an Item


Android Listview custom layout with filter example
Android Listview custom layout with filter example

Source for Activity - AndroidListViewCustomLayoutActivity.java

package com.as400samplecode;

import java.util.ArrayList;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.Filter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener;

public class AndroidListViewCustomLayoutActivity extends Activity {

 MyCustomAdapter dataAdapter = null;

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

  //Generate list View from ArrayList
  displayListView();

 }

 private void displayListView() {

  //Array list of countries
  ArrayList<Country> countryList = new ArrayList<Country>();
  Country country = new Country("AFG","Afghanistan","Asia",
    "Southern and Central Asia");
  countryList.add(country);
  country = new Country("ALB","Albania","Europe","Southern Europe");
  countryList.add(country);
  country = new Country("DZA","Algeria","Africa","Northern Africa");
  countryList.add(country);
  country = new Country("ASM","American Samoa","Oceania","Polynesia");
  countryList.add(country);
  country = new Country("AND","Andorra","Europe","Southern Europe");
  countryList.add(country);
  country = new Country("AGO","Angola","Africa","Central Africa");
  countryList.add(country);
  country = new Country("AIA","Anguilla","North America","Caribbean");
  countryList.add(country);

  //create an ArrayAdaptar from the String Array
  dataAdapter = new MyCustomAdapter(this,
    R.layout.country_info, countryList);
  ListView listView = (ListView) findViewById(R.id.listView1);
  // Assign adapter to ListView
  listView.setAdapter(dataAdapter);

  //enables filtering for the contents of the given ListView
  listView.setTextFilterEnabled(true);

  listView.setOnItemClickListener(new OnItemClickListener() {
   public void onItemClick(AdapterView<?> parent, View view,
     int position, long id) {
    // When clicked, show a toast with the TextView text
    Country country = (Country) parent.getItemAtPosition(position);
    Toast.makeText(getApplicationContext(),
      country.getCode(), Toast.LENGTH_SHORT).show();
   }
  });

  EditText myFilter = (EditText) findViewById(R.id.myFilter);
  myFilter.addTextChangedListener(new TextWatcher() {

  public void afterTextChanged(Editable s) {
  }

  public void beforeTextChanged(CharSequence s, int start, int count, int after) {
  }

  public void onTextChanged(CharSequence s, int start, int before, int count) {
   dataAdapter.getFilter().filter(s.toString());
  }
  });

 }

 private class MyCustomAdapter extends ArrayAdapter<Country> {

  private ArrayList<Country> originalList;
  private ArrayList<Country> countryList;
  private CountryFilter filter;

  public MyCustomAdapter(Context context, int textViewResourceId, 
    ArrayList<Country> countryList) {
   super(context, textViewResourceId, countryList);
   this.countryList = new ArrayList<Country>();
   this.countryList.addAll(countryList);
   this.originalList = new ArrayList<Country>();
   this.originalList.addAll(countryList);
  }

  @Override
  public Filter getFilter() {
   if (filter == null){
    filter  = new CountryFilter();
   }
   return filter;
  }


  private class ViewHolder {
   TextView code;
   TextView name;
   TextView continent;
   TextView region;
  }

  @Override
  public View getView(int position, View convertView, ViewGroup parent) {

   ViewHolder holder = null;
   Log.v("ConvertView", String.valueOf(position));
   if (convertView == null) {

   LayoutInflater vi = (LayoutInflater)getSystemService(
     Context.LAYOUT_INFLATER_SERVICE);
   convertView = vi.inflate(R.layout.country_info, null);

   holder = new ViewHolder();
   holder.code = (TextView) convertView.findViewById(R.id.code);
   holder.name = (TextView) convertView.findViewById(R.id.name);
   holder.continent = (TextView) convertView.findViewById(R.id.continent);
   holder.region = (TextView) convertView.findViewById(R.id.region);

   convertView.setTag(holder);

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

   Country country = countryList.get(position);
   holder.code.setText(country.getCode());
   holder.name.setText(country.getName());
   holder.continent.setText(country.getContinent());
   holder.region.setText(country.getRegion());

   return convertView;

  }

  private class CountryFilter extends Filter
  {

   @Override
   protected FilterResults performFiltering(CharSequence constraint) {

    constraint = constraint.toString().toLowerCase();
    FilterResults result = new FilterResults();
    if(constraint != null && constraint.toString().length() > 0)
    {
    ArrayList<Country> filteredItems = new ArrayList<Country>();

    for(int i = 0, l = originalList.size(); i < l; i++)
    {
     Country country = originalList.get(i);
     if(country.toString().toLowerCase().contains(constraint))
      filteredItems.add(country);
    }
    result.count = filteredItems.size();
    result.values = filteredItems;
    }
    else
    {
     synchronized(this)
     {
      result.values = originalList;
      result.count = originalList.size();
     }
    }
    return result;
   }

   @SuppressWarnings("unchecked")
   @Override
   protected void publishResults(CharSequence constraint, 
     FilterResults results) {

    countryList = (ArrayList<Country>)results.values;
    notifyDataSetChanged();
    clear();
    for(int i = 0, l = countryList.size(); i < l; i++)
     add(countryList.get(i));
    notifyDataSetInvalidated();
   }
  }


 }
}

Source for POJO - Country.java

package com.as400samplecode;

public class Country {
 
 String code = null;
 String name = null;
 String continent = null;
 String region = null;
 
 public Country(String code, String name, String continent, String region) {
  super();
  this.code = code;
  this.name = name;
  this.continent = continent;
  this.region = region;
 }
 
 public String getCode() {
  return code;
 }
 public void setCode(String code) {
  this.code = code;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public String getContinent() {
  return continent;
 }
 public void setContinent(String continent) {
  this.continent = continent;
 }
 public String getRegion() {
  return region;
 }
 public void setRegion(String region) {
  this.region = region;
 }

 @Override
 public String toString() {
  return  code + " " + name + " "
    + continent + " " + region;
 }
 
 
}

Source for Main Screen Layout - 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:padding="10dp"
  android:text="@string/some_text" android:textSize="20sp" />

 <EditText android:id="@+id/myFilter" android:layout_width="match_parent"
  android:layout_height="wrap_content" android:ems="10" 
  android:hint="@string/some_hint">
  <requestFocus />
 </EditText>

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

</LinearLayout>

Source for Custom List Layout - country_info.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="wrap_content"
    android:orientation="vertical"
    android:padding="6dip" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:text="Code: "
        android:textAppearance="?android:attr/textAppearanceMedium" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/textView1"
        android:layout_below="@+id/textView1"
        android:text="Name: "
        android:textAppearance="?android:attr/textAppearanceMedium" />

    <TextView
        android:id="@+id/textView3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/textView2"
        android:layout_below="@+id/textView2"
        android:text="Continent: "
        android:textAppearance="?android:attr/textAppearanceMedium" />

    <TextView
        android:id="@+id/textView4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/textView3"
        android:layout_below="@+id/textView3"
        android:text="Region: "
        android:textAppearance="?android:attr/textAppearanceMedium" />

    <TextView
        android:id="@+id/continent"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/textView3"
        android:layout_alignBottom="@+id/textView3"
        android:layout_toRightOf="@+id/textView3"
        android:text="TextView" />

    <TextView
        android:id="@+id/region"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/textView4"
        android:layout_alignBottom="@+id/textView4"
        android:layout_alignLeft="@+id/continent"
        android:text="TextView" />

    <TextView
        android:id="@+id/name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/textView3"
        android:layout_toRightOf="@+id/textView3"
        android:text="TextView" />

    <TextView
        android:id="@+id/code"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/textView2"
        android:layout_alignLeft="@+id/name"
        android:text="TextView" />

</RelativeLayout>

Source for application variables - strings.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

 <string name="app_name">Android ListView</string>
 <string name="some_text">
  Display and Filter some North American Countries!
 </string>
 <string name="some_hint">
  Type here to filter&#8230;
 </string>
</resources>

Source for application manifest - AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 package="com.as400samplecode" android:versionCode="1"
 android:versionName="1.0">

 <uses-sdk android:minSdkVersion="15" />

 <application android:icon="@drawable/ic_launcher"
  android:label="@string/app_name" 
  android:theme="@android:style/Theme.Holo.Light">
  <activity android:name=".AndroidListViewFilterActivity"
   android:label="@string/app_name">
   <intent-filter>
    <action android:name="android.intent.action.MAIN" />

    <category android:name="android.intent.category.LAUNCHER" />
   </intent-filter>
  </activity>
 </application>

</manifest>

References