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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12456525/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 10:42:54  来源:igfitidea点击:

How to filter ListView using getFilter() in BaseAdapter

androidfilterandroid-listviewbaseadapter

提问by Abhishek Dhiman

In my application I have create a custom list view and I want to implement a filter so that the list can be filtered according to the text entered in the EditText. I am using a BaseAdapter as a separate class and I am calling that class in my Main Activity. I have also implemented the addTextChangedListener() in my main activity and I have also implemented the getFilter() in my BaseAdapter class. But I don't know how can I use getFilter() and can filter my list accordingly. In the list I am adding the values from a JSON URL. Please help me in letting me know that how can I use the getFilter() in order to filter my List.

在我的应用程序中,我创建了一个自定义列表视图,我想实现一个过滤器,以便可以根据 EditText 中输入的文本过滤列表。我使用 BaseAdapter 作为一个单独的类,我在我的主活动中调用该类。我还在我的主要活动中实现了 addTextChangedListener(),我还在 BaseAdapter 类中实现了 getFilter()。但我不知道如何使用 getFilter() 并相应地过滤我的列表。在列表中,我添加了来自 JSON URL 的值。请帮助我让我知道如何使用 getFilter() 来过滤我的列表。

The code of Activity class:

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

}

The code of BaseAdapter class:

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

Thanks in advance...

提前致谢...

回答by Omar Abdan

i hope this example could help you

我希望这个例子可以帮助你

in the Main_Activity

在 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

            }
        });

in your adapter put this class to use it in getfilter method

在您的适配器中放置此类在 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();
        }

    }

also in your adapter return instance from filter_hereclass

也在您的适配器返回实例中来自filter_here

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

回答by Mtl Dev

In your BaseAdapter, store two copies of the list, one original, and one filtered. And change all references in your BaseAdapter, to only use the filtered list.

在您的 BaseAdapter 中,存储列表的两份副本,一份是原始的,一份是过滤后的。并更改 BaseAdapter 中的所有引用,以仅使用过滤列表。

1) in your activity, activate the filter on your ListView: lv.setTextFilterEnabled(true);

1) 在您的活动中,激活ListView上的过滤器: lv.setTextFilterEnabled(true);

2) in your textWatcher, trigger the filter on your listadapter srchadptr.getFilter().filter(s)

2) 在你的 textWatcher 中,在你的列表适配器 srchadptr.getFilter().filter(s) 上触发过滤器

3) Update your baseadapter to store two copies of the data, and change references to refer to the filtered list instead of the original list.

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();
        }
    };
}

回答by Vlad

I find working with filters not all that convenient.. How i do it is:

我发现使用过滤器并不是那么方便..我是怎么做的:

        ((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) {}

    });
}

Note that you'll have to change your adapter to work with the mDisplayedList instead of the mFullList.. and that's it.

请注意,您必须更改适配器才能使用 mDisplayedList 而不是 mFullList .. 就是这样。

This might give some overhead when your list contains ALOT of entries.. but i've worked like this with a list of +-300 items and i didn't notice anything.

当您的列表包含大量条目时,这可能会带来一些开销.. 但我已经像这样处理了 +-300 个项目的列表,但我没有注意到任何事情。

Hope it helps, Vlad

希望它有所帮助,弗拉德