Add a search filter on RecyclerView with Cards?

priyank picture priyank · Apr 22, 2015 · Viewed 34.4k times · Source

I found solutions for filters on ListView and SearchView on RecyclerView separately, but I wish to combine them. Is it even possible?

Answer

Konrad Krakowiak picture Konrad Krakowiak · Apr 22, 2015

Yes it is possible Your RecyclerView.Adapter can implement Filterable. After that you have to override Filter getFilter() method.

You have to define your own filter as is shown in the code below:

@Override
public Filter getFilter() {
    return new YourFilterClass();
}

YourFilterClass

class YourFilterClass extends Filter {

        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            //Here you have to implement filtering way
            final FilterResults results = new FilterResults();
            //logic to filtering
            results.values = ...
            results.count = ...
            return results;
        }

        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {
            // here you can use result - (f.e. set in in adapter list)
        }
}

Example

public class UserListAdapter extends RecyclerView.Adapter<UserListAdapter.ViewHolder> implements Filterable {

    private final List<User> userList;

    private final List<User> filteredUserList;

    private UserFilter userFilter;

    public UserListAdapter(Context context) {
        this.userList =new ArrayList<>();
        this.filteredUserList = new ArrayList<>();
    }


    ///... other methods

    @Override
    public Filter getFilter() {
       if(userFilter == null)
             userFilter = new UserFilter(this, userList);
        return userFilter;
    }

    private static class UserFilter extends Filter {

        private final UserListAdapter adapter;

        private final List<User> originalList;

        private final List<User> filteredList;

        private UserFilter(UserListAdapter adapter, List<User> originalList) {
            super();
            this.adapter = adapter;
            this.originalList = new LinkedList<>(originalList);
            this.filteredList = new ArrayList<>();
        }

        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            filteredList.clear();
            final FilterResults results = new FilterResults();

            if (constraint.length() == 0) {
                filteredList.addAll(originalList);
            } else {
                final String filterPattern = constraint.toString().toLowerCase().trim();

                for (final User user : originalList) {
                    if (user.getName().contains(filterPattern)) {
                        filteredList.add(user);
                    }
                }
            }
            results.values = filteredList;
            results.count = filteredList.size();
            return results;
        }

        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {
            adapter.filteredUserList.clear();
            adapter.filteredUserList.addAll((ArrayList<User>) results.values);
            adapter.notifyDataSetChanged();
        }
    }
}

After that in the place when you want to filtering call:

userListAdapter.getFilter().filter(text)