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 :)
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);
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 };
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 {
public int imageResourceId;
public String name;
}
}
The layout of each player item football_player_item.xml.
="1.0"="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 :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
.
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();
ArrayList<FootballPlayer> filters = new ArrayList<FootballPlayer>();
if (constraint == null || constraint.length() == 0) {
for (FootballPlayer player : listBackupDatas) {
filters.add(player);
}
results.values = filters;
results.count = filters.size();
} else {
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.:)
History
- 2013 - 08 - 11: First version.