Click here to Skip to main content
Click here to Skip to main content

Image list view filter

By , 26 Sep 2013
Rate this:
Please Sign up or sign in to vote.

Introduction

In Smart Phones, it is easy to find an application which has a filter function in a list view. The filter function will help the user to easily find his record which he wants to view. But how do we do it?

I will give a simple sample to help you clear it.

  • Display a list of football players. Each player will have:
    • Player thumbnail.
    • Player name.
  • An edit text where the user can input the character which is the beginning of the player's name. Based on the input text, the list will be filtered by the player's name and display.
    • E.g.: If the user wants to view Ronaldo, he can input R, next o, ...

I hope you enjoy it Smile | :)

Using the code

Prepare to display list view data

Please refer to the code below to display list player data.

public class MainActivity extends Activity {

    public ArrayList<FootballPlayer> listDatas = new ArrayList<MainActivity.FootballPlayer>();
    public FootballPlayerAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Create dummy data
        String[] userNames = new String[] { "Ronaldo", "Zidance", "Cong Vinh",
                "Huynh Duc", "Gerrard", "Nagatomo", "Messi", "Minh Phuong",
                "neymar" };
        int[] playerDrawableResourceIds = new int[] { R.drawable.ronaldo,
                R.drawable.zindance, R.drawable.congvinh, R.drawable.huynhduc,
                R.drawable.gerrard, R.drawable.nagatomo, R.drawable.messi,
                R.drawable.minhphuong, R.drawable.neymar };

        // Prepare dummy data
        for (int i = 0; i < playerDrawableResourceIds.length; i++) {
            FootballPlayer footballPlayer = new FootballPlayer();
            footballPlayer.name = userNames[i];
            footballPlayer.imageResourceId = playerDrawableResourceIds[i];
            listDatas.add(footballPlayer);
        }

        ListView lv = (ListView) findViewById(R.id.lv);
        adapter = new FootballPlayerAdapter();
        lv.setAdapter(adapter);
    }

    private class FootballPlayerAdapter extends BaseAdapter {
        @Override
        public int getCount() {
            return listDatas.size();
        }

        @Override
        public FootballPlayer getItem(int position) {
            return listDatas.get(position);
        }

        @Override
        public long getItemId(int position) {
            return 0;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            PlayerViewHolder holder;
            if (convertView == null) {
                convertView = (ViewGroup) LayoutInflater.from(
                        getApplicationContext()).inflate(
                        R.layout.football_player_item, null);
                holder = new PlayerViewHolder();
                holder.name = (TextView) convertView
                        .findViewById(R.id.player_name);
                holder.thumb = (ImageView) convertView
                        .findViewById(R.id.player_thumbnail);
                convertView.setTag(holder);
            } else {
                holder = (PlayerViewHolder) convertView.getTag();
            }
            holder.name.setText(getItem(position).name);
            holder.thumb.setImageResource(getItem(position).imageResourceId);
            return convertView;
        }
    }

    private static class PlayerViewHolder {
        public ImageView thumb;
        public TextView name;
    }

    public class FootballPlayer {
        /** Keep the id of resource file which is player's thumbnail. */
        public int imageResourceId;
        /** Player name. */
        public String name;
    }
} 

The layout of each player item football_player_item.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="35dp"
    android:orientation="horizontal" >

    <ImageView
        android:id="@+id/player_thumbnail"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_gravity="center_vertical"
        android:layout_marginLeft="5dp" />

    <TextView
        android:id="@+id/player_name"
        android:textColor="@android:color/black"
        android:layout_width="match_parent"
        android:layout_height="35dp"
        android:layout_marginLeft="10dp"
        android:layout_weight="1"
        android:ellipsize="end"
        android:gravity="center_vertical"
        android:maxLines="1"
        android:orientation="vertical"
        android:singleLine="true"
        android:textSize="16sp" />

</LinearLayout>

The code above has some dummy data, and in fact you must create it and save to a drawable resource folder. With me, there is no way easier than downloading from the web Big Grin | :-D

int[] playerDrawableResourceIds = new int[] { R.drawable.ronaldo,
R.drawable.zindance, R.drawable.congvinh, R.drawable.huynhduc,
R.drawable.gerrard, R.drawable.nagatomo, R.drawable.messi,
R.drawable.minhphuong, R.drawable.neymar };  

And this is the result:

Add edit text to filter list data by player's name

  • When input text to edit text, it will auto filter the current list data.
  • If edit text is empty, display full list

To filter list, beside  ArrayList<FootballPlayer> listDatas which is used as adapter data, create a backup data list ArrayList<FootballPlayer> listBackupDatas.

// Prepare dummy data
for (int i = 0; i < playerDrawableResourceIds.length; i++) {
    FootballPlayer footballPlayer = new FootballPlayer();
    footballPlayer.name = userNames[i];
    footballPlayer.imageResourceId = playerDrawableResourceIds[i];
    listDatas.add(footballPlayer);
    listBackupDatas.add(footballPlayer);
}  

Add to the main layout an edit text where the input filter text will be.

EditText filterText  = (EditText) findViewById(R.id.filter_text);
filterText .addTextChangedListener(new TextWatcher() {
    @Override
    public void onTextChanged(CharSequence s, int arg1, int arg2,
            int arg3) {
        adapter.getFilter().filter(s.toString());
    }
    @Override
    public void beforeTextChanged(CharSequence arg0, int arg1,
            int arg2, int arg3) {
    }
    @Override
    public void afterTextChanged(Editable arg0) {
    }
}); 

The above code means that, we will control when the filter edit text is changed. If there is changing, we call the filter function in the player adapter.

adapter.getFilter().filter(s.toString()); 

The PlayerFilter class will be implemented as here:

private class PlayerFilter extends Filter {
    @Override
    protected FilterResults performFiltering(CharSequence constraint) {
        FilterResults results = new FilterResults();
        // We implement here the filter logic
        ArrayList<FootballPlayer> filters = new ArrayList<FootballPlayer>();
        if (constraint == null || constraint.length() == 0) {
            // No filter implemented we return all the list
            for (FootballPlayer player : listBackupDatas) {
                filters.add(player);
            }
            results.values = filters;
            results.count = filters.size();
        } else {
            // We perform filtering operation
            for (FootballPlayer row : listBackupDatas) {
                if (((FootballPlayer) row).name.toUpperCase().startsWith(
                        constraint.toString().toUpperCase())) {
                    filters.add(row);
                }
            }
            results.values = filters;
            results.count = filters.size();
        }
        return results;
    }

    @Override
    protected void publishResults(CharSequence constraint,
            FilterResults results) {
        if (results.count == 0) {
            listDatas.clear();
            adapter.notifyDataSetChanged();
        } else {
            listDatas.clear();
            ArrayList<FootballPlayer> resultList = (ArrayList<FootballPlayer>) results.values;
            for (FootballPlayer row : resultList) {
                listDatas.add(row);
            }
            adapter.notifyDataSetChanged();
        }
    }
}

performFiltering

This method is invoked when there is a callback onTextChanged  of filterText.

  • The input text of filterText is the parameter constraint.
  • Based on constraint text, suitable data will be returned. 

With this sample, it will find in listBackupDatas the player who has the name whose starting text is constraint, and add to an array list.

The return data of method is a FilterResults object. It contains:

  • values: the arraylist contains players whose name start with constraint text.
  • count: the number of above arraylist.

publishResults

This method is invoked to notify the filter result to the UI thread. With this sample:

  • If there is no data returned from performFiltering the data of list view listDatas will be clear and adapter.notifyDataSetChanged(). The list will be empty in this case, of course.
  • Otherwise, based on the FilterResults which was returned from performFiltering method, add all player of FilterResults.values to adapter.listDatas then call adapter.notifyDataSetChanged() to refresh the list view.

And final result is here:

Points of interest

With my experience, it is better if for each filter list we create two list data, once for displaying and and once for backup. It will help with easy controlling. In this sample, they are:

public ArrayList<FootballPlayer> listDatas = new ArrayList<MainActivity.FootballPlayer>();
public ArrayList<FootballPlayer> listBackupDatas = new ArrayList<MainActivity.FootballPlayer>(); 
  • listDatas will be used as the main data of the adapter. Its data will be changed while filtering.
  • listBackupDatas is used as backup data.

For more, you can use the edit text in this tip to have an edit text with search icon.Smile | :)

History

  • 2013 - 08 - 11: First version.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

huyletran

Vietnam Vietnam
I'm Java developer.
I started Java web coding from 2007 to 2010. After that, I began to develop Android from 2010 to now.
In my thinking, sharing and connecting is the best way to develop.
I would like to study more via yours comments and would like to have relationship with more developers in the world.

Comments and Discussions

 
GeneralMy vote of 5 PinmemberZinto8919-Nov-13 22:03 
GeneralMy vote of 5 PinmemberMember 1018792727-Sep-13 8:50 
GeneralMy vote of 5 PinmemberThatsAlok6-Sep-13 18:42 
nice
GeneralMy vote of 5 PinmemberArash M. Dehghani17-Aug-13 7:51 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140415.2 | Last Updated 26 Sep 2013
Article Copyright 2013 by huyletran
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid