类图:
通常可以将SearchView和ListView结合,实现数据的搜索和过滤。
1.监听SearchView,SearchView.setOnQueryTextListener(OnQueryTextListener listener);
2.开启ListView的过滤功能,listView.setTextFilterEnabled(true)。必须开启,否则不会过滤;
3..当SearchView接收到输入事件后,调用ListView.setFilterText(filterText)方法,该方法会通过Adapter得到Filter,然后调用Filter.filter(filterText):
- public void setFilterText(String filterText) {
- // TODO: Should we check for acceptFilter()?
- if (mTextFilterEnabled && !TextUtils.isEmpty(filterText)) {
- createTextFilter(false);
- // This is going to call our listener onTextChanged, but we might not
- // be ready to bring up a window yet
- mTextFilter.setText(filterText);
- mTextFilter.setSelection(filterText.length());
- if (mAdapter instanceof Filterable) {
- // if mPopup is non-null, then onTextChanged will do the filtering
- if (mPopup == null) {
- Filter f = ((Filterable) mAdapter).getFilter();
- f.filter(filterText);
- }
- // Set filtered to true so we will display the filter window when our main
- // window is ready
- mFiltered = true;
- mDataSetObserver.clearSavedState();
- }
- }
- }
4.Filter.filter(filterText)方法最终会调用Filter.performFiltering(filterText)和Filter.publishResults(CharSequence filterText, FilterResults results)。performFiltering(filterText)方法完成过滤处理并且返回结果FilterResults,而publishResults(CharSequence filterText, FilterResults results)则根据返回的结果进行相应的处理。
5.Filter.publishResults(CharSequence filterText, FilterResults results)调用了BaseAdapter.notifyDataSetChanged()方法,该方法用于当Adapter的数据发生变化时,通知UI主线程根据新的数据绘制界面:
- @Override
- protected void publishResults(CharSequence constraint, FilterResults results) {
- //noinspection unchecked
- mObjects = (List<T>) results.values;
- if (results.count > 0) {
- notifyDataSetChanged();
- } else {
- notifyDataSetInvalidated();
- }
- }
数据过滤就这样完成了。
下面给出例子。
布局文件filter_activity.xml:
- <?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="vertical" >
- <SearchView
- android:id="@+id/searchView1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" >
- </SearchView>
- <ListView
- android:id="@+id/listView1"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" >
- </ListView>
- </LinearLayout>
类文件MainActivity.java:
- package com.zzj.ui.filterdemo;
- import android.app.Activity;
- import android.os.Bundle;
- import android.widget.ArrayAdapter;
- import android.widget.ListView;
- import android.widget.SearchView;
- import android.widget.SearchView.OnQueryTextListener;
- import com.zzj.ui.R;
- public class MainActivity extends Activity implements OnQueryTextListener {
- private ListView listView;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.filter_activity);
- SearchView searchView = (SearchView) findViewById(R.id.searchView1);
- searchView.setOnQueryTextListener(this);
- searchView.setSubmitButtonEnabled(false);
- searchView.setIconifiedByDefault(false);
- listView = (ListView) findViewById(R.id.listView1);
- ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
- android.R.layout.simple_list_item_1, new String[] { "Bei jing",
- "Shang hai", "Chang sha", "Chang chun", "Nan jing",
- "Dong jing", "Ji nan", "Qing dao", "Xiang tan",
- "Zhu zhou", "Heng yang" });
- listView.setAdapter(adapter);
- // 开启过滤功能
- listView.setTextFilterEnabled(true);
- }
- @Override
- public boolean onQueryTextSubmit(String query) {
- return false;
- }
- @Override
- public boolean onQueryTextChange(String newText) {
- if (newText == null || newText.length() == 0) {
- listView.clearTextFilter();
- } else {
- listView.setFilterText(newText);
- }
- return true;
- }
- }
效果图:
如图所示,弹出了一个浮动框,这是listView.setFilterText(filterText)弹出来的。如果不想要这个浮动框,可以先获取Filter,然后调用Filter.filter(filterText)。
修改SearchView的监听函数如下:
- @Override
- public boolean onQueryTextChange(String newText) {
- ListAdapter adapter = listView.getAdapter();
- if (adapter instanceof Filterable) {
- Filter filter = ((Filterable) adapter).getFilter();
- if (newText == null || newText.length() == 0) {
- filter.filter(null);
- } else {
- filter.filter(newText);
- }
- }
- return true;
- }
使用这种方法不需要开启ListView的过滤功能。效果如下:
上面使用的是ArrayAdapter的过滤功能,我们也可以继承BaseAdapter,然后实现Filterable接口,定义自己的过滤器。