How to filter ListView using getFilter() in BaseAdapter

前端 未结 3 1457
长发绾君心
长发绾君心 2020-11-30 09:14

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 usin

相关标签:
3条回答
  • 2020-11-30 10:01

    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.

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

    2) in your textWatcher, trigger the filter on your listadapter 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.

    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 讨论(0)
  • 2020-11-30 10:10

    i hope this example could help you

    in the 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

    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_here class

    @Override
        public Filter getFilter() {
            // TODO Auto-generated method stub
            return filter;
        }
    
    0 讨论(0)
  • 2020-11-30 10:11

    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.

    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.

    Hope it helps, Vlad

    0 讨论(0)
提交回复
热议问题