Search code examples
javaandroidlistviewandroid-fragmentsandroid-filterable

Filter a ListView with custom adapter and custom row in a fragment


I have a ListView with a custom adapter in a fragment. Everything works fine but now I'm trying to implement a way for filtering the list when typing in an EditText (I've tried a SearchView but it did not work either). Each row has two EditTexts and a ImageView.

In OnCreateView:

lst=(ListView)rootView.findViewById(R.id.lst);
lst.setTextFilterEnabled(true);
mainAd = new mArrayAdapter(getActivity(),R.layout.row,downList); //it's more complicated than this but normally the ListView is populated correctly
lst.setAdapter(mainAd);
lst.setTextFilterEnabled(true);
edit = (EditText) rootView.findViewById(R.id.txtexample);
edit.addTextChangedListener(new TextWatcher() {
    @Override
        public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

        }

        @Override
        public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
            mainAd.getFilter().filter(charSequence.toString());
        }

        @Override
        public void afterTextChanged(Editable editable) {

        }
});
return rootView;

The mArrayAdapter:

private class mArrayAdapter extends ArrayAdapter<Exhibition> implements Filterable{

    Context context;
    int layoutResourceId;
    ArrayList<Exhibition> list;
    ValueFilter valueFilter;
    ArrayList<Exhibition> filterList;

    mArrayAdapter(Context context, int layoutResourceId, ArrayList<Exhibition>  data){
        super(context, layoutResourceId, data);
        this.context=context;
        this.layoutResourceId=layoutResourceId;
        this.list=data;
        this.filterList =data;
    }

    @Override
    @NonNull
    public View getView(int position, View convertView, @NonNull ViewGroup parent) {
        View row;
        Exhibition ex;
        if(convertView==null){
            row= getActivity().getLayoutInflater().inflate(R.layout.row,parent,false);
        }
        else row = convertView;
        TextView ttl = (TextView)row.findViewById(R.id.title);
        TextView descr = (TextView)row.findViewById(R.id.descr);
        ImageView header = (ImageView)row.findViewById(R.id.hd);

        ex = downList.get(position);

        ttl.setText(ex.name);
        descr.setText(ex.description);

        byte[] decoded = Base64.decode(ex.image,Base64.DEFAULT);
        Bitmap decodedBitmap = BitmapFactory.decodeByteArray(decoded,0,decoded.length);
        header.setImageBitmap(decodedBitmap);
        return row;

    }

    @Override
    public Filter getFilter() {
        if (valueFilter == null) {
            valueFilter = new ValueFilter();
        }
        return valueFilter;
    }

    private class ValueFilter extends Filter {
        @Override
        protected FilterResults performFiltering(CharSequence constraint) {

            String filtString = constraint.toString().toLowerCase();
            FilterResults results = new FilterResults();
            if(constraint == null || constraint.length() == 0){
                results.values = filterList;
                results.count = filterList.size();
            }
            else {

                List<Exhibition> nExhList = new ArrayList<>();

                for(Exhibition e : list){
                    if (e.getName().toLowerCase().startsWith(constraint.toString().toLowerCase())){
                        nExhList.add(e);
                    }
                }

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

            }
            return results;

        }

        @Override
        protected void publishResults(CharSequence constraint,
                                      FilterResults results) {
            if(results.count==0){
                notifyDataSetInvalidated();
            }
            else{
                list = (ArrayList<Exhibition>)results.values;
                notifyDataSetChanged();
            }
        }

    }

}

I don't know why it's not working. Thanks in advance.


Solution

  • I solved my problem.

    I add the changes I did for make it works but, if you have the same problem, note that at THIS link there is an example I made to filter correctly a ListView with an EditText and a SearchView.

    For first, in edit.addTextChangedListener:

    edit.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
    
            }
    
            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                if (i2 < i1) {
                    mainAd.resetData();  //if I delete characters I would like to show the original list
                }
                mainAd.getFilter().filter(charSequence.toString());
            }
    
            @Override
            public void afterTextChanged(Editable editable) {
    
            }
        });
    

    For second, in the mArrayAdapter I checked the right variables (for example, I was calling the original ArrayList in getView()) and I add three methods that are needed:

    @Override
    public int getCount(){
        return list.size();
    }
    
    @Override
    public Exhibition getItem (int pos){
        return list.get(pos);
    }
    
    void resetData() {
        list = originalList;
    }
    

    (I changed the name of filterList in originalList)

    The ValueFilter is the following:

    private class ValueFilter extends Filter {
            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                FilterResults results = new FilterResults();
                if(constraint == null || constraint.length() == 0){
                    results.values = originalList;
                    results.count = originalList.size();
                }
                else {
    
                    List<Exhibition> nExhList = new ArrayList<>();
    
                    for(Exhibition e : list){
                        if (e.getName().toUpperCase().startsWith(constraint.toString().toUpperCase())){
                            nExhList.add(e);
                        }
                    }
    
                    results.values= nExhList;
                    results.count=nExhList.size();
                }
                return results;
            }
    
            @Override
            protected void publishResults(CharSequence constraint,
                                          FilterResults results) {
                if(results.count==0){
                    notifyDataSetInvalidated();
                }
                else{
                    list = (ArrayList<Exhibition>)results.values;
                    notifyDataSetChanged();
                }
            }
    
        }