为自定义 Listview 添加搜索到自定义 SimpleAdapter

Posted

技术标签:

【中文标题】为自定义 Listview 添加搜索到自定义 SimpleAdapter【英文标题】:Adding Search to Custom SimpleAdapter for Custom Listview 【发布时间】:2017-08-24 14:31:59 【问题描述】:

我的 ListView 工作得非常好。现在我想在 listItem 行的一些文本视图上添加搜索工具。

例如,我在工具栏中有一个 editText 或 Searchview。 我的 ListView 有一项,即状态字段。现在我只想从列表视图中搜索状态。

我在互联网上找到了许多解决方案,但我有我的自定义简单适配器类,我不知道如何在其中添加搜索。

这是我的 ExtendedSimpleAdapter 代码:

public class ExtendedSimpleAdapter extends SimpleAdapter implements Filterable 
List<? extends Map<String, ?>> map; // if fails to compile, replace with List<HashMap<String, Object>> map


String[] from;
int layout;
int[] to;
private ArrayList<Map<String, ?>> mUnfilteredData;
//private ArrayList<Product> mDisplayedValues;
Context context;
private Filter mFilter;
LayoutInflater mInflater;

public ExtendedSimpleAdapter(Context context, List<? extends Map<String, ?>> data, // if fails to compile, do the same replacement as above on this line
                             int resource, String[] from, int[] to) 
    super(context, data, resource, from, to);
    layout = resource;
    map = data;
    this.from = from;
    this.to = to;
    this.context = context;


@Override
public int getCount() 
    return map.size();



@Override
public Object getItem(int position) 
    return map.get(position);



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



@Override
public View getView(int position, View convertView, ViewGroup parent) 
    mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    return this.createViewFromResource(position, convertView, parent, layout);



private View createViewFromResource(int position, View convertView,
                                    ViewGroup parent, int resource) 
    View v;
    if (convertView == null) 
        v = mInflater.inflate(resource, parent, false);
     else 
        v = convertView;
    

    this.bindView(position, v);

    return v;



private void bindView(int position, View view) 
    final Map dataSet = map.get(position);
    if (dataSet == null) 
        return;
    

    final ViewBinder binder = super.getViewBinder();
    final int count = to.length;

    for (int i = 0; i < count; i++) 
        final View v = view.findViewById(to[i]);
        if (v != null) 
            final Object data = dataSet.get(from[i]);
            String text = data == null ? "" : data.toString();
            if (text == null) 
                text = "";
            

            boolean bound = false;
            if (binder != null) 
                bound = binder.setViewValue(v, data, text);
            

            if (!bound) 
                if (v instanceof Checkable) 
                    if (data instanceof Boolean) 
                        ((Checkable) v).setChecked((Boolean) data);
                     else if (v instanceof TextView) 
                        // Note: keep the instanceof TextView check at the bottom of these
                        // ifs since a lot of views are TextViews (e.g. CheckBoxes).
                        setViewText((TextView) v, text);
                     else 
                        throw new IllegalStateException(v.getClass().getName() +
                                " should be bound to a Boolean, not a " +
                                (data == null ? "<unknown type>" : data.getClass()));
                    
                 else if (v instanceof TextView) 
                    // Note: keep the instanceof TextView check at the bottom of these
                    // ifs since a lot of views are TextViews (e.g. CheckBoxes).
                    setViewText((TextView) v, text);
                 else if (v instanceof ImageView) 
                    if (data instanceof Integer) 
                        setViewImage((ImageView) v, (Integer) data);
                     else if (data instanceof Bitmap) 
                        setViewImage((ImageView) v, (Bitmap) data);
                     else 
                        setViewImage((ImageView) v, text);
                    
                 else if (v instanceof RatingBar) 
                    float score = Float.parseFloat(data.toString());  //2
                    ((RatingBar) v).setRating(score);
                 else 
                    throw new IllegalStateException(v.getClass().getName() + " is not a " +
                            " view that can be bounds by this SimpleAdapter");
                
            
        
    



private void setViewImage(ImageView v, Bitmap bmp) 
    v.setImageBitmap(bmp);


public Filter getFilter() 
    if (mFilter == null) 
        mFilter = new SimpleFilter();
    
    return mFilter;


private class SimpleFilter extends Filter 

    @Override
    protected FilterResults performFiltering(CharSequence prefix) 
        FilterResults results = new FilterResults();

        if (mUnfilteredData == null) 
            mUnfilteredData = new ArrayList<Map<String, ?>>(map);
        

        if (prefix == null || prefix.length() == 0) 
            ArrayList<Map<String, ?>> list = mUnfilteredData;
            results.values = list;
            results.count = list.size();
         else 
            String prefixString = prefix.toString().toLowerCase();

            ArrayList<Map<String, ?>> unfilteredValues = mUnfilteredData;
            int count = unfilteredValues.size();

            ArrayList<Map<String, ?>> newValues = new ArrayList<Map<String, ?>>(count);

            for (int i = 0; i < count; i++) 
                Map<String, ?> h = unfilteredValues.get(i);
                if (h != null) 

                    int len = to.length;

                    for (int j = 0; j < len; j++) 
                        String str = (String) h.get(from[j]);

                        String[] words = str.split(" ");
                        int wordCount = words.length;

                        for (int k = 0; k < wordCount; k++) 
                            String word = words[k];

                            if (word.toLowerCase().startsWith(prefixString)) 
                                newValues.add(h);
                                break;
                            
                        
                    
                
            

            results.values = newValues;
            results.count = newValues.size();
        

        return results;
    

    @Override
    protected void publishResults(CharSequence constraint, FilterResults results) 
        //noinspection unchecked
        map = (List<Map<String, ?>>) results.values;
        if (results.count > 0) 
            notifyDataSetChanged();
         else 
            notifyDataSetInvalidated();
        
    



这里我将适配器设置为 listview :

 evc = new ExtendedSimpleAdapter(Users.this, contactList,R.layout.new_dr_list,
                new String[]"picture","name","speciality" ,"status","education","experience","rating",
                new int[]R.id.imug_p1,R.id.usr_dname,R.id.dspecs,R.id.statusp,R.id.educ,R.id.exper,R.id.ratingBar1);
        usersList.setAdapter(evc);
        ((BaseAdapter) evc).notifyDataSetChanged();

如您所见,我在 simpleadapter 中有一个标签状态,我如何对其执行搜索..??

编辑

现在当我从 searview 栏中搜索内容时出现此错误。

java.lang.NullPointerException: Attempt to invoke interface method 'int java.util.List.size()' on a null object reference
                                                                           at com.adnan.zwd.hidoctor.Chat.ExtendedSimpleAdapter.getCount(ExtendedSimpleAdapter.java:52)
                                                                           at android.widget.AdapterView.checkFocus(AdapterView.java:739)
                                                                           at android.widget.AdapterView$AdapterDataSetObserver.onInvalidated(AdapterView.java:862)
                                                                           at android.widget.AbsListView$AdapterDataSetObserver.onInvalidated(AbsListView.java:6211)
                                                                           at android.database.DataSetObservable.notifyInvalidated(DataSetObservable.java:50)
                                                                           at android.widget.BaseAdapter.notifyDataSetInvalidated(BaseAdapter.java:59)
                                                                           at com.adnan.zwd.hidoctor.Chat.ExtendedSimpleAdapter$SimpleFilter.publishResults(ExtendedSimpleAdapter.java:222)
                                                                           at android.widget.Filter$ResultsHandler.handleMessage(Filter.java:282)
                                                                           at android.os.Handler.dispatchMessage(Handler.java:102)
                                                                           at android.os.Looper.loop(Looper.java:148)
                                                                           at android.app.ActivityThread.main(ActivityThread.java:5417)
                                                                           at java.lang.reflect.Method.invoke(Native Method)
                                                                           at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
                                                                           at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

【问题讨论】:

【参考方案1】:

您可以在 cicle 中使用 if(from[i].contains(constraints)),将结果保存在 String[] 中,最后将该数组分配给 Adapter 以便它使用它。不过我建议你改成 ReciclerView 而不是 ListView。

示例...没有对其进行测试,但应该可以工作或至少对您有所帮助..我希望。有趣的事实......我也从你的代码中学到了一些东西。非常感谢您的机会。

 @Override
    public Filter getFilter() 
        Filter filter = new Filter() 

            @SuppressWarnings("unchecked")
            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) 
            from = (String[]) results.values; // change dateset
              notifyDataSetChanged();
                 // notifies the data with new filtered values
            

            @Override
            protected FilterResults performFiltering(CharSequence constraint) 
                FilterResults results = new Filter.FilterResults();        // Holds the results of a filtering operation in values
               // ArrayList<Product> FilteredArrList = new ArrayList<Product>();

             String [] filtered = new String[from.length];
                int index=0;
              for(int i=0;i<from.length;i++)
                  if(from[i].contains(constraint))
                  
                      filtered[index++]=from[i];
                  
                results.values = filtered;
                results.count=index;

                return results;
            
        ;
        return filter;
    

【讨论】:

你能举个例子吗?我是自定义适配器的新手。即使我发现 recyclerView 真的很难和我一起去,请建议我应该如何让它工作。谢谢 那是因为我更新了数据源但没有更新 List&lt;? extends Map&lt;String, ?&gt;&gt; map; 对象,对不起,你用它来获取数据集中的对象数量,实际上可能只是通过更新“地图”你可以让它工作。因此,在 publishResults() 中放置您的地图代码以仅包含过滤后的结果。

以上是关于为自定义 Listview 添加搜索到自定义 SimpleAdapter的主要内容,如果未能解决你的问题,请参考以下文章

如何添加到自定义列表视图用户控制编辑项目列组等任务?

将搜索框添加到自定义地图 javascript

Android - ListView 中的 EditTexts 绑定到自定义 ArrayAdapter - 跟踪更改

为自定义 ArrayAdapter 实现 Fiterable 接口

渐变颜色到自定义视图

添加到自定义 UICollectionViewCell 时出现意外的 CAShapeLayer 行为