如何在BaseAdapter中使用getFilter()过滤ListView

4
在我的应用程序中,我创建了一个自定义列表视图,并希望实现过滤器,以便可以根据在EditText中输入的文本对列表进行过滤。我正在使用BaseAdapter作为单独的类,并在我的主Activity中调用该类。我还在我的主Activity中实现了addTextChangedListener(),并在我的BaseAdapter类中实现了getFilter()。但是我不知道如何使用getFilter()来过滤我的列表。在列表中,我从JSON URL添加值。请告诉我如何使用getFilter()来过滤我的列表。
Activity类的代码:
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    lv = (ListView)findViewById(R.id.listView1);
    et1 = (EditText)findViewById(R.id.editText1);
    inflator = getLayoutInflater();
    et1.addTextChangedListener(this);
    JsonParser jParser = new JsonParser();
    JSONObject json = jParser.getJSONfromUrl(url);
    try
    {
        JSONArray explore = json.getJSONArray("explore");
        for(int i=0; i<explore.length(); i++)
        {
            JSONObject exp = explore.getJSONObject(i);
            list.add(exp.getString("username"));
        }
    }
    catch(JSONException e)
    {
        e.printStackTrace();
    }

    srchadptr = new SearchAdapter(this, inflator, list);
    lv.setAdapter(srchadptr);
}

public void afterTextChanged(Editable s) {
    // TODO Auto-generated method stub
    srchadptr.getFilter().filter(s);
}

public void beforeTextChanged(CharSequence s, int start, int count,
        int after) {
    // TODO Auto-generated method stub

}

public void onTextChanged(CharSequence s, int start, int before, int count) {
    // TODO Auto-generated method stub

}

BaseAdapter类的代码:
public class SearchAdapter extends BaseAdapter implements Filterable {

    Context context;
    LayoutInflater inflater;
    Button btn;
    View vw;
    ArrayList<String> list = new ArrayList<String>();

    public SearchAdapter(Context context,   LayoutInflater inflater, ArrayList<String> list) {
        // TODO Auto-generated constructor stub
        this.context = context;
        this.inflater = inflater;
        this.list = list;
    }

    /*public CharSequence filter(CharSequence cs) {
        return cs;
    }*/

    public int getCount() {
        // TODO Auto-generated method stub
        return list.size();
    }

    public Object getItem(int position) {
        // TODO Auto-generated method stub
        return position;
    }

    public long getItemId(int position) {
        // TODO Auto-generated method stub
        return position;
    }



    public View getView(final int position, View convertView, ViewGroup parent) {
        // TODO Auto-generated method stub
        LinearLayout ll = (LinearLayout) vw;
        final EditText edt = ((EditText)ll.getChildAt(0));
        vw = inflater.inflate(R.layout.list_items, null);
        ImageView img = (ImageView)vw.findViewById(R.id.imageView1);
        TextView tv = (TextView)vw.findViewById(R.id.textView1);
        btn = (Button)vw.findViewById(R.id.button1);
        tv.setText(String.valueOf(list.get(position)));
        btn.setText(String.valueOf(list.get(position)));
        btn.setOnClickListener(new OnClickListener() {

            public void onClick(View v) {
                // TODO Auto-generated method stub
                Toast.makeText(context, list.get(position), Toast.LENGTH_LONG).show();
            }
        });
        return vw;
    }

    public android.widget.Filter getFilter() {
        // TODO Auto-generated method stub
        return new android.widget.Filter() {

            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
                // TODO Auto-generated method stub

            }

            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                // TODO Auto-generated method stub
                return null;
            }
        };
    }
}

预先感谢您的帮助...


1
https://dev59.com/IWoy5IYBdhLWcg3wPbyd#8678198 - Lalit Poptani
很高兴知道一个可工作的示例对你没有用处!!! - Lalit Poptani
@Abhishek 如果你在谷歌上搜索 @Override 问题,你可能会得到很多解决方案...其中一个是将编译器从1.5更改为1.6...从 项目属性- Java编译器 - MKJParekh
需要调用 notifyDataSetChanged() API。 - Ramindu Weeraman
我只需要写nptifyDataSetChanged()吗?我应该在哪里写这个?请给我一些基础教程...仅凭一行代码我无法理解... - Abhishek Dhiman
显示剩余4条评论
3个回答

10

希望这个例子能对你有所帮助

在Main_Activity中

    EditText etSearch;
    BaseAdapterFilterable adapter;

    etSearch.addTextChangedListener(new TextWatcher() {

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                // Listview name of the class
                Listview.this.adapter.getFilter().filter(s);
            }

            @Override
            public void beforeTextChanged(CharSequence s, int start, int count,
                    int after) {
                // TODO Auto-generated method stub

            }

            @Override
            public void afterTextChanged(Editable s) {
                // TODO Auto-generated method stub

            }
        });

在你的适配器中,将这个类放入getfilter方法中以使用它。

public class filter_here extends Filter{

        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            // TODO Auto-generated method stub

            FilterResults Result = new FilterResults();
            // if constraint is empty return the original names
            if(constraint.length() == 0 ){
                Result.values = Original_Names;
                Result.count = Original_Names.size();
                return Result;
            }

            ArrayList<String> Filtered_Names = new ArrayList<String>();
            String filterString = constraint.toString().toLowerCase();
            String filterableString;

            for(int i = 0; i<Original_Names.size(); i++){
                filterableString = Original_Names.get(i);
                if(filterableString.toLowerCase().contains(filterString)){
                    Filtered_Names.add(filterableString);
                }
            }
            Result.values = Filtered_Names;
            Result.count = Filtered_Names.size();

            return Result;
        }

        @Override
        protected void publishResults(CharSequence constraint,FilterResults results) {
            // TODO Auto-generated method stub
            Names = (ArrayList<String>) results.values;
            notifyDataSetChanged();
        }

    }

在你的适配器中,也要返回来自filter_here类的实例。

@Override
    public Filter getFilter() {
        // TODO Auto-generated method stub
        return filter;
    }

你说的最后一行是什么意思:“在你的适配器中也要返回来自filter_here类的实例”?在哪里需要添加这个返回过滤器的代码? - ray
在您的适配器构造函数中,使用“filter_here”类初始化对象:“filter_here filter = new filter_here();” 覆盖getfilter方法并返回filter。 - Omar Abdan
@OmarAbdan,你能帮忙解决这个问题吗:http://stackoverflow.com/questions/20524417/listview-is-blank-while-using-getfilter-function - Si8
在你的适配器中,只需将上面的方法放在getView()旁边即可... ----------getView 结束--------- @Override public Filter getFilter() { // TODO Auto-generated method stub return filter_here; } --------------适配器类结束------------ - EsmaeelQash

2
在您的BaseAdapter中,存储两份列表副本,一份原始的,一份过滤后的。并且将BaseAdapter中所有引用更改为仅使用过滤后的列表。
1)在您的活动中,激活ListView上的过滤器: lv.setTextFilterEnabled(true);
2)在您的TextWatcher中,触发ListAdapter上的过滤器 srchadptr.getFilter().filter(s)
3)更新您的BaseAdapter以存储两份数据,并将引用更改为引用过滤后的列表而不是原始列表。
public class SearchAdapter extends BaseAdapter implements Filterable {

List<String> list = new ArrayList<String>();
List<String> listFiltered = new ArrayList<String>();

public SearchAdapter(Context context, ArrayList<String> list) {
    this.context = context;
    this.inflater = LayoutInflater.from(context)
    this.list = list;
    this.listFiltered=list;
}

public int getCount() {
    return listFiltered.size();//note the change
}

public Object getItem(int position) {
    return listFiltered.get(position);//note the change
}

//only altered lines shown in this function (change ``list`` to ``listFiltered``)
public View getView(final int position, View convertView, ViewGroup parent) {
    tv.setText(String.valueOf(listFiltered.get(position)));
    btn.setText(String.valueOf(listFiltered.get(position)));
    btn.setOnClickListener(new OnClickListener() {
        public void onClick(View v) {
            Toast.makeText(context, listFiltered.get(position), Toast.LENGTH_LONG).show();
        }
    });
}

//now write your filter function

@Override
public Filter getFilter() {
    return new Filter() {
        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            FilterResults results = new FilterResults();

            if (constraint == null || constraint.length() == 0) {
                //no constraint given, just return all the data. (no search)
                results.count = list.size();
                results.values = list;
            } else {//do the search
                List<String> resultsData = new ArrayList<>();
                String searchStr = constraint.toString().toUpperCase();
                for (String s : list)
                    if (s.toUpperCase().contains(searchStr)) resultsData.add(s);
                results.count = resultsData.size();
                results.values = resultsData;
            }

            return results;
        }

        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {
            listFiltered = (ArrayList<String>) results.values;
            notifyDataSetChanged();
        }
    };
}

0

我发现使用过滤器并不是很方便。我的做法是:

        ((EditText)findViewById(R.id.etSearch)).addTextChangedListener(new TextWatcher(){

        private boolean mCountIncreased;
        @Override
        public void afterTextChanged(Editable s) {

            if (s.toString().length() == 0){
                mDisplayedList.clear();
                mDisplayedList.addAll(mFullList);
                mListAdapter.notifyDataSetChanged();
                return;
            }

            if (mCountIncreased){
                mDisplayedList.clear();
                mDisplayedList.addAll(mFullList);
            }

            List<Item> toRemove = new ArrayList<Item>();
            for (Item item : mDisplayedList){
                if (someCondition)
                        toRemove.add(currency);
                }
            }

            mDisplayedList.removeAll(toRemove);
            mListAdapter.notifyDataSetChanged();
        }

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            mCountIncreased = after <= count;
        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {}

    });
}

请注意,您将不得不更改适配器以使用mDisplayedList而不是mFullList。就是这样。
当您的列表包含大量条目时,这可能会带来一些开销。但是我已经用这种方式处理了大约300个条目的列表,并没有注意到任何问题。
希望能有所帮助, Vlad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接