在andorid开发中,有时候会遇到这样的情况,界面中有一个SearchView,需要在其中输入内容来过滤ListView中的内容
大致的做法如下:
1. ListView的adpter实现Filterable接口
/**
* Adapter for exam/project list in session view.
*
*/
public class SessionSimpleAdapter extends SimpleAdapter implements Filterable {
private static final String TAG = "SessionSimpleAdapter";
private final Context mContext;
/**
* point to the data associated with the ListView, this should not be
* changed, otherwise method "notifyDatasetChanged" would make no sense.
*/
private ArrayList<HashMap<String, String>> data;
/**
* store the whole data, be used to search matched data.
*/
private ArrayList<HashMap<String, String>> mOriginData;
private int resource;
private String[] from;
private int[] to;
private MyFilter myFilter;
public SessionSimpleAdapter(Context context,
List<? extends Map<String, ?>> data) {
super(context, data, 0, new String[] {}, new int[] {});
this.mContext = context;
this.data = (ArrayList<HashMap<String, String>>) data;
this.mOriginData = new ArrayList<HashMap<String, String>>(this.data);
}
class ViewHolder {
ImageView icon;
TextView[] showTv;
ProgressBar downloadProgressBar;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
HashMap<String, String> map = data.get(position);
String type = map.get("type");
String uuid = map.get("uuid");
String title = map.get("name");
String description = map.get("description");
final ViewHolder holder;
if (convertView == null) {
Log.d(TAG, "convertView == null");
holder = new ViewHolder();
convertView = inflater.inflate(R.layout.material_item, null);
holder.icon = (ImageView) convertView.findViewById(R.id.icon);
holder.showTv = new TextView[2];
holder.showTv[0] = (TextView) convertView.findViewById(R.id.name);
holder.showTv[1] = (TextView) convertView
.findViewById(R.id.description);
convertView.setTag(holder);
} else {
Log.d(TAG, "convertView != null");
holder = (ViewHolder) convertView.getTag();
}
if (type.equals("p")) {
holder.icon.setImageResource(R.drawable.project_icon);
holder.showTv[0].setText("Project - " + map.get("name"));
// need to clear the listener which might be associated with the
// view last time.
convertView.setOnClickListener(null);
} else {
holder.icon.setImageResource(R.drawable.exam_icon);
holder.showTv[0].setText("Exam - " + map.get("name"));
convertView.setOnClickListener(mExamListener);
}
holder.showTv[1].setText(map.get("description"));
return convertView;
}
@Override
public Filter getFilter() {
if (myFilter == null) {
myFilter = new MyFilter();
}
return myFilter;
}
class MyFilter extends Filter {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
// filter the origin data to get result.
ArrayList<HashMap<String, String>> newResult = new ArrayList<HashMap<String, String>>();
for (Iterator iterator = mOriginData.iterator(); iterator.hasNext();) {
HashMap<String, String> hashMap = (HashMap<String, String>) iterator
.next();
if (hashMap.get("name").contains(constraint)
|| hashMap.get("description").contains(constraint)) {
newResult.add(hashMap);
}
}
results.values = newResult;
results.count = newResult.size();
return results;
}
@Override
protected void publishResults(CharSequence constraint,
FilterResults results) {
data.clear();
data.addAll((Collection<? extends HashMap<String, String>>) results.values);
Log.d(TAG, "search over, size:" + data.size());
if (results.count > 0) {
notifyDataSetChanged();
} else {
notifyDataSetInvalidated();
}
}
}
private OnClickListener mExamListener = new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setClass(mContext, ExamActivity.class);
mContext.startActivity(intent);
}
};
}
实现Filterable接口后该列表中的数据就可以按照规则过滤了。
2. 在Activity中为SearchView设定SearchView.OnQueryTextListener监听,在其回调方法中直接用如下代码实现对adapter数据源的过滤
@Override
public boolean onQueryTextChange(String newText) {
if (TextUtils.isEmpty(newText)) {
mMaterialListView.clearTextFilter();
} else {
mMaterialListView.setFilterText(newText.toString());
}
return true;
}
这样用户在SearchView中输入string时,就可以按照之前adpter中设定的过滤规则来过滤,同时更新视图(在 Filter的publishResult方法中实现)。
上述的代码有一个问题:当用户在SearchView中输入字符时,确实可以过滤并更新列表,不过界面中始终有一个悬浮窗在显示过滤字符,在SearchView等类中均没有发现相关的方法去屏蔽掉该悬浮窗。
解决方法很简单,将过滤方法的调用从ListView交给filter本身就可以:
@Override
public boolean onQueryTextChange(String newText) {
if (TextUtils.isEmpty(newText)) {
mMaterialListView.clearTextFilter();
} else {
// below code committed will lead to a popup window when entering
// search word, use the next line to work around the problem.
// mMaterialListView.setFilterText(newText.toString());
adapter.getFilter().filter(newText);
}
return true;
}