Android ListView Custom Filter and Filterable interface

This post describes how to use Android Listview custom filter. In the previous post we showed the way we can programming a custom adapter and a custom layout. One aspect we didn’t cover by now, is how we can filter the items in the ListView. In this post we describe how we can develop an android listview custom filter to filter items inside a ListView while the user writes words inside an input field. We can use the example shown in the last post and modify it. What do we need to do it?

  • Modify the custom adapter, PlanetAdapter so that it will be able to filter the items
  • Add an input field where the user can insert the keys to filter the ListView

Let’s start then.

Android ListView Custom filter

 

Modify the custom adapter so that it implements the Filterable interface

If we didn’t use a custom adapter witha  custom object inside the ListView, the things would be much easier. For example, if we used just String as item content we simply could add a few lines of code to make our list filterable; but we have a custom layout that uses not a simple String but a complex object (i.e. Planet). So we need first modify our custom adapter (PlanetAdapter) so that it implements the android.widget.Filter interface. This interface requires we implement just only one method called getFilter() that returns a android.widget.Filter object. The problem is the way we can create this filter. Very easy!

[java]private class PlanetFilter extends Filter {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
….
}

@Override
protected void publishResults(CharSequence constraint,FilterResults results) {
…..
}
}
[/java]

To enable Android Listview custom filter, we create a private class called PlanetFilter that extends the android.widget.Filter. This class has two abstract methods:

  • FilterResults performFiltering(CharSequence constraint) : invoked in worker thread, that has the task to filter the results according to the constraint
  • void publishResults(CharSequence constraint,FilterResults results): that has the task to show the result set created by performingFiltering method

Let’s suppose we want to filter the planet list using the name attribute. In our case, then, the constraint can be the initial letters of the planet name, so that if the planet starts with those letters we show it otherwise we hide it.

[java]@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
// We implement here the filter logic
if (constraint == null || constraint.length() == 0) {
// No filter implemented we return all the list
results.values = planetList;
results.count = planetList.size();
}
else {
// We perform filtering operation
List<Planet> nPlanetList = new ArrayList<Planet>();

for (Planet p : planetList) {
if (p.getName().toUpperCase()
.startsWith(constraint.toString().toUpperCase()))
nPlanetList.add(p);
}

results.values = nPlanetList;
results.count = nPlanetList.size();
}
return results;
}[/java]

In this method, we have to return a FilterResults that has two static attributes called values and count. Values is a list of values to be shown while count is the number of these values. The first thing we do in this method is to verify if the constraint is null or empty, in this case we don’t have to filter the result and simply

results.values = planetList;
results.count = planetList.size();

In other words all the list. If the constraints aren’t null or empty we simply select the planet with its name starting with the constraint, as shown below.

[java]List<Planet> nPlanetList = new ArrayList<Planet>();

for (Planet p : planetList) {
if (p.getName().toUpperCase()
.startsWith(constraint.toString().toUpperCase()))
nPlanetList.add(p);
}

results.values = nPlanetList;
results.count = nPlanetList.size();
[/java]

The next step is publishing the result.

[java]@Override
protected void publishResults(CharSequence constraint,
FilterResults results) {

// Now we have to inform the adapter about the new list filtered
if (results.count == 0)
notifyDataSetInvalidated();
else {
planetList = (List&lt;Planet&gt;) results.values;
notifyDataSetChanged();
}
}
[/java]

We said before that the PlanetAdapter has to implement Filterable interface and it has to implement getFilter() method:

[java]@Override
public Filter getFilter() {
if (planetFilter == null)
planetFilter = new PlanetFilter();
return planetFilter;
}
[/java]

This is code is quite trivial, we simply invalidate the result set if the result list is empty or we notify that the result set is changed.

It is done!….quite done!…We need now adding just an input field where user can insert the keyword to filter the result. The new layout becomes:

[xml]<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:focusable="true"
android:focusableInTouchMode="true">

<EditText
android:id="@+id/editTxt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:maxLines="1" />

<ListView android:id="@+id/listView"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:layout_weight="1"/>

<Button android:id="@+id/addBtn"
android:text="Add planet"
android:onClick="addPlanet"
android:layout_weight="0.5"
android:layout_height="80dp"
android:layout_width="match_parent"/>

</LinearLayout>
[/xml]

In the main activity, we have to add some listener attached to EditText so that when user writes inside it we can filter the list items.

[java]editTxt.addTextChangedListener(new TextWatcher() {

@Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
System.out.println("Text ["+s+"]");
aAdpt.getFilter().filter(s.toString());
}

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

@Override
public void afterTextChanged(Editable s) {
}
});
[/java]

Running the code we have:

     androdi_listview_filter android_listview_filtered_itmes

Tricks about Android listview custom filter

One simple trick we have to use is to make soft keyboard hidden at the app startup. As soon as the app starts the EditText gains the focus and the OS shows the keyboard covering the list items. If we don’t want this we can simply “move” the focus somewhere else:

[xml]android:focusable="true"
android:focusableInTouchMode="true"[/xml]

Source code here

    1. Ederson Schmidt November 6, 2012
    2. Francesco Azzola November 6, 2012
    3. Francesco Azzola November 6, 2012
      • Ederson Schmidt November 7, 2012
    4. Francesco Azzola November 7, 2012
    5. Anonymous November 22, 2012
    6. Francesco Azzola November 22, 2012
    7. Anonymous December 11, 2012
      • Francesco Azzola December 11, 2012
      • Anonymous December 11, 2012
      • Anonymous December 11, 2012
    8. Francesco Azzola December 11, 2012
      • Anonymous December 11, 2012
      • Francesco Azzola December 11, 2012
      • Anonymous December 14, 2012
      • Anonymous December 14, 2012
      • Anonymous December 14, 2012
      • Francesco Azzola December 16, 2012
      • Anonymous December 18, 2012
    9. Anonymous December 22, 2012
    10. Francesco Azzola January 19, 2013
    11. imran khan February 25, 2013
    12. Anonymous March 12, 2013
    13. Anonymous2 May 3, 2013
    14. Mick Hearne May 4, 2013
    15. survivingwithandroid May 4, 2013
    16. Mick Hearne May 4, 2013
    17. survivingwithandroid May 4, 2013
    18. Mick Hearne May 4, 2013
    19. dentex June 17, 2013
    20. survivingwithandroid June 18, 2013
    21. dentex June 18, 2013
    22. dentex June 18, 2013
    23. dentex June 18, 2013
    24. survivingwithandroid June 18, 2013
    25. dentex June 18, 2013
    26. dentex June 18, 2013
    27. Rohit June 28, 2013
    28. survivingwithandroid July 1, 2013
    29. Rohit July 2, 2013
    30. dentex August 26, 2013
    31. Rontrile November 17, 2013
    32. Estuardo León December 4, 2013
    33. jaffar April 1, 2014
    34. Aryanata April 23, 2014
    35. pkpdeveloper May 11, 2014
    36. Deepak D July 2, 2014
    37. Deepak D July 4, 2014
    38. Ersin July 28, 2014
    39. Pagio August 7, 2014
    40. Jorge Casariego September 16, 2014
    41. Jorge Casariego September 16, 2014
    42. kelvin October 4, 2014
    43. kelvin October 4, 2014
    44. anurag February 15, 2015
    45. anurag February 15, 2015
    46. Junior Frogie March 23, 2015
    47. Junior Frogie March 23, 2015
    48. Sami June 4, 2015
    49. Sami June 4, 2015
    50. NaseemH July 3, 2015
    51. NaseemH July 3, 2015
    52. Vipin Kumar November 2, 2015
    53. Quentin Rouet October 18, 2016
    54. Shrikant Sharma November 25, 2016

    Add Your Comment