SearchView filter with RecyclerView

14,814

Solution 1

You can create class which extends Filter

class YourFilterClass extends Filter {

private List<Contact> contactList;
private List<Contact> filteredContactList;
private ContactsAdapter adapter;

    public YourFilterClass(List<Contact> contactList, ContactsAdapter adapter) {
     this.adapter = adapter;
     this.contactList = contactList;
     this.filteredContactList = new ArrayList();
    }

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

    //here you need to add proper items do filteredContactList
     for (final Contact item : contactList) {
            if (item.getName().toLowerCase().trim().contains("pattern")) { 
                filteredContactList.add(item);
            }
        }

        results.values = filteredContactList;
        results.count = filteredContactList.size();
        return results;
    }

    @Override
    protected void publishResults(CharSequence constraint, FilterResults results) {
        adapter.setList(filteredContactList);
        adapter.notifyDataSetChanged();
    }

}

And then you can add this Filter to yours ContactsAdapter.

public class ContactsAdapter extends RecyclerView.Adapter<ContactsAdapter.ContactVH> {

List<Contact> mContact;
List<Contact> mContactFilter;
YourFilterClass filter;

Context mContext;

public ContactsAdapter(Context context, List<Contact> contact) {
    this.mContact = contact;
    this.mContactFilter = contact;
    this.mContext = context;
    filter = new YourFilterClass(mContact, this);
}

@Override
public ContactVH onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_item_contact, parent, false);
    ContactVH viewHolder = new ContactVH(view);
    return viewHolder;
}

@Override
public void onBindViewHolder(ContactVH holder, int position) {
    holder.name.setText(mContactFilter.get(position).getName());
}
// set adapter filtered list
public void setList(List<Contact> list) {
    this.mContactFilter = list;
}
//call when you want to filter
public void filterList(String text) {
    filter.filter(text);
}

@Override
public int getItemCount() {
    return mContactFilter.size();
}

class ContactVH extends RecyclerView.ViewHolder {
    @BindView(R.id.contact_name)
    TextView name;

    public ContactVH(View itemView) {
        super(itemView);
        ButterKnife.bind(this, itemView);
    }

}

}

Solution 2

searchview filter woth recyclerview

In your adapter class implement filterable and overide it's method.

    @Override
public Filter getFilter() {

    Filter filter = new Filter() {
        @Override
        protected FilterResults performFiltering(CharSequence charSequence) {
            FilterResults filterResults = new FilterResults();

            if(charSequence == null | charSequence.length() == 0){
                filterResults.count = getUserModelListFiltered.size();
                filterResults.values = getUserModelListFiltered;

            }else{
                String searchChr = charSequence.toString().toLowerCase();

                List<UserModel> resultData = new ArrayList<>();

                for(UserModel userModel: getUserModelListFiltered){
                    if(userModel.getUserName().toLowerCase().contains(searchChr)){
                        resultData.add(userModel);
                    }
                }
                filterResults.count = resultData.size();
                filterResults.values = resultData;

            }

            return filterResults;
        }

        @Override
        protected void publishResults(CharSequence charSequence, FilterResults filterResults) {

            userModelList = (List<UserModel>) filterResults.values;
            notifyDataSetChanged();

        }
    };
    return filter;
}

in your main activity create searchview and listen to onQueryTextChange.

 @Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.menu, menu);

    MenuItem menuItem = menu.findItem(R.id.search_view);

    SearchView searchView = (SearchView) menuItem.getActionView();

    searchView.setMaxWidth(Integer.MAX_VALUE);

    searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
        @Override
        public boolean onQueryTextSubmit(String query) {
            return false;
        }

        @Override
        public boolean onQueryTextChange(String newText) {

            usersAdapter.getFilter().filter(newText);
            return true;
        }
    });



    return  true;
}

full tutorial and source code. Recyclerview with search / filter

Share:
14,814
Štěpán Záliš
Author by

Štěpán Záliš

Updated on June 04, 2022

Comments

  • Štěpán Záliš
    Štěpán Záliš about 2 years

    I have tried to implement a SearchView with suggestions (filter) in Fragment, but I have not managed it. I tried almost every tutorial but nothing worked for me. I would appreciate any help. Thank you

    XML ...

        <!--appBar layout-->
        <android.support.design.widget.AppBarLayout
            android:id="@+id/appBarLayout"
            android:fitsSystemWindows="true"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize">
    
            <!--searchView layout-->
            <android.support.v7.widget.SearchView
                android:id="@+id/search_view"
                app:layout_scrollFlags="scroll|enterAlways"
                android:iconifiedByDefault="false"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                app:closeIcon="@drawable/ic_clear_white_18dp"
                app:searchIcon="@drawable/ic_search_white_24dp"
                app:queryHint="@string/search_contact"
                app:iconifiedByDefault="false"
                android:background="@color/colorPrimary"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
                app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
    
           </android.support.design.widget.AppBarLayout>
    
            <!-- recycler view-->
            <android.support.v7.widget.RecyclerView
                app:layout_behavior="@string/appbar_scrolling_view_behavior"
                android:id="@+id/recycler_view"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />
    

    Fragment

    @Override
        public View onCreateView(LayoutInflater inflater, final ViewGroup container, Bundle savedInstanceState) {
            View view = inflater.inflate(R.layout.fragment_contact_list, container, false);
    
            searchView = (SearchView)view.findViewById(R.id.search_view);
            fabButton = (FloatingActionButton)view.findViewById(R.id.fab_button);
    
            //recycler view
            recyclerView = (RecyclerView)view.findViewById(R.id.recycler_view);
            recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
            contacts = SugarRecord.listAll(Contact.class);
            contactsAdapter = new ContactsAdapter(getActivity(), contacts);
            recyclerView.setAdapter(contactsAdapter);
    
            searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
                @Override
                public boolean onQueryTextSubmit(String query) {
                    return false;
                }
    
                @Override
                public boolean onQueryTextChange(String newText) {
                    // TODO: setFilter
    
                    return true;
                }
            });
    
            return view;
    

    Adapter

    public class ContactsAdapter extends RecyclerView.Adapter<ContactsAdapter.ContactVH> {
    
        List<Contact> mContact;
        List<Contact> mContactFilter;
    
        Context mContext;
    
        public ContactsAdapter(Context context, List<Contact> contact) {
            this.mContact = contact;
            this.mContext = context;
        }
    
        @Override
        public ContactVH onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_item_contact, parent, false);
            ContactVH viewHolder = new ContactVH(view);
            return viewHolder;
        }
    
        @Override
        public void onBindViewHolder(ContactVH holder, int position) {
            holder.name.setText(mContact.get(position).getName());
        }
    
        @Override
        public int getItemCount() {
            return mContact.size();
        }
    
        class ContactVH extends RecyclerView.ViewHolder {
            @BindView(R.id.contact_name)
            TextView name;
    
            public ContactVH(View itemView) {
                super(itemView);
                ButterKnife.bind(this, itemView);
            }
    
        }
    
    }