在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; }