Android 自定义过滤搜索框

时间:2022-10-12 11:24:58

简单的说就是ListView上面有一个SearchBox,然后searchbox里输入内容后对下面listview进行过滤。

涉及的控件:ListView必须有,EditText用来自定义SearchBox

大概就是这样:

Android 自定义过滤搜索框         Android 自定义过滤搜索框

先看这个有图片的EditText,实现方法有两个,一是用相对布局RelativeLayout + ImageView + EditText。

二是直接用EditText的一个属性DrawableLeft,简单的UI这个就可以实现了

所以这个Activity的布局就很简单,可以用ListActivity实现:

<RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >

<EditText
android:id="@+id/searchbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:drawableLeft="@drawable/searchbox"
android:hint="Search"
android:drawablePadding="5dp"
android:singleLine="true"
android:ems="10" >
<requestFocus />
</EditText>


<ListView
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/searchbox">
</ListView>

</RelativeLayout>

再说过滤功能:这个感觉不想搜索,就像是简单的过滤,如果涉及到去数据库取数据那个才是搜索了

用到了Filterable接口,Filter类

要让数据有过滤功能,我们需要在继承的BaseAdapter的基础上再实现Filterable接口的getFilter方法,同时在Adapter内部写一个继承Filter的内部类来完成过滤功能:

private class ListAdapter extends BaseAdapter implements Filterable {

private List<Person> list;

private Context context;

private PersonFilter filter;

public ListAdapter(List<Person> list, Context context) {
this.list = list;
this.context = context;
}

@Override
public int getCount() {
return list.size();
}

@Override
public Object getItem(int position) {
return list.get(position);
}

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

@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(context).inflate(R.layout.list_item, null);
}
Person p = list.get(position);
TextView firstname = (TextView)convertView.findViewById(R.id.firstname);
TextView lastname = (TextView)convertView.findViewById(R.id.lastname);
TextView age = (TextView)convertView.findViewById(R.id.age);

firstname.setText(p.firstname);
lastname.setText(p.lastname);
age.setText(p.age + "");
return convertView;
}

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

private class PersonFilter extends Filter {

private List<Person> original;

public PersonFilter(List<Person> list) {
this.original = list;
}

@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
if (constraint == null || constraint.length() == 0) {
results.values = original;
results.count = original.size();
} else {
List<Person> mList = new ArrayList<Person>();
for (Person p: original) {
if (p.firstname.toUpperCase().startsWith(constraint.toString().toUpperCase())
|| p.lastname.toUpperCase().startsWith(constraint.toString().toUpperCase())
|| new String(p.age + "").toUpperCase().startsWith(constraint.toString().toUpperCase())) {
mList.add(p);
}
}
results.values = mList;
results.count = mList.size();
}
return results;
}

@Override
protected void publishResults(CharSequence constraint,
FilterResults results) {
list = (List<Person>)results.values;
notifyDataSetChanged();
}

}
}

Filter类中的两个方法看名字就是知道一个是执行过滤的,一个刷新listview数据展现结果的。其中我采用了前缀匹配,就是用输入的字符串和ListView里的所有Person的各个属性的前缀做比较。也可以用更加复杂的匹配,例如正则表达式。

关键在于EditText里的数据是如何传入的,要写一个TextWater,并且要让EditText注册一下这个监听器:

private TextWatcher filterTextWatcher = new TextWatcher() {

@Override
public void afterTextChanged(Editable s) {

}

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

}

@Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
listAdapter.getFilter().filter(s); //这里传入数据就可以了
}

};

以上关键代码。非关键代码是Person类以及List_Item的布局:

private class Person {
public String firstname;
public String lastname;
public int age;

public Person(String firtname, String lastname, int age) {
this.firstname = firtname;
this.lastname = lastname;
this.age = age;
}
}

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >

<TextView
android:id="@+id/firstname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:text="Firstname" />

<TextView
android:id="@+id/lastname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:text="Lastname" />

<TextView
android:id="@+id/age"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:text="Age" />

</LinearLayout>