Any time I find a self filtering search box that works properly, my life is improved! Good UI and all that :) I find auto complete a great way to search and thought I'd share. There is no rocket science here, I just pieced this together from a few various examples.
First a simple activity main:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<!-- Pretty hint text, and maxLines -->
<EditText
android:id="@+id/searchbox1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="@string/filter_hint"
android:inputType="text"
android:maxLines="1"/>
<!-- Set height to 0, and let the weight param expand it -->
<!-- Note the use of the default ID! This lets us use a ListActivity still! -->
<ListView android:id="@+id/listview1"
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="1" />
</LinearLayout>
Next in my ActivityMain I create a helper method getNames() to load in the data. Obviously you'll do this in your own unique way. Also note the TextWatcher, this is pretty simple.
private TextWatcher filterTextWatcher = 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) {
arrayAdapter.getFilter().filter(s);
}
};
private ArrayList<String> getNames(){
String[] names = getResources().getStringArray(R.array.planets_array);
ArrayList<String> listNames = new ArrayList<String>();
for(String name: names){
listNames.add(name);
}
return listNames;
}
Then in onCreate we put it all together:
mFriendsList = (ListView) findViewById(R.id.listview1);
//Apply Filter
filterText = (EditText) findViewById(R.id.searchbox1);
filterText.addTextChangedListener(filterTextWatcher);
arrayAdapter = new newNameAdapter(this, getNames());
arrayAdapter.sort();
mFriendsList.setAdapter(arrayAdapter);
Finally the complicated (ish) bit is the Adapter.
package com.example.testleaguefinder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Locale;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.TextView;
public class newNameAdapter extends BaseAdapter implements Filterable{
Context context;
ArrayList<String> names;
private LayoutInflater mInflater;
private GameFilter filter;
ArrayList<String> orig;
public newNameAdapter(Context _context, ArrayList<String> _names) {
this.context = _context;
this.names = _names;
filter = new GameFilter();
mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public int getCount() {
return names.size();
}
@Override
public String getItem(int position) {
return names.get(position);
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = mInflater.inflate(R.layout.listview_names, null);
}
TextView txtName = (TextView) convertView.findViewById(R.id.listview_names_name);
txtName.setText(getItem(position));
return convertView;
}
public void sort(){
Collections.sort(names, new Comparator<String>() {
@Override
public int compare(String fruite1, String fruite2)
{
return fruite1.compareTo(fruite2);
}
});
}
@Override
public Filter getFilter() {
return filter;
}
private class GameFilter extends Filter {
public GameFilter() {
}
@Override
protected FilterResults performFiltering(CharSequence constraint) {
String lowerConstraint = constraint.toString();
FilterResults oReturn = new FilterResults();
ArrayList<String> results = new ArrayList<String>();
String league;
if (orig == null){
orig = names;
}
if (lowerConstraint != null){
lowerConstraint = lowerConstraint.toLowerCase(Locale.UK);
if (orig != null && orig.size() > 0) {
for (String g : orig) {
league = g.toLowerCase(Locale.UK);
if (league.contains(lowerConstraint)){
results.add(g);
}
}
}
oReturn.values = results;
}
return oReturn;
}
@SuppressWarnings("unchecked")
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
names = (ArrayList<String>)results.values;
notifyDataSetChanged();
}
}
}
Most of it should be fairly standard, the only interesting bit should be the Filter. All we're doing really is taking the entered text and lower casing it. Then we loop through the list of entries and find any that contain the filter string.
Simples!