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
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
Author by
Štěpán Záliš
Updated on June 04, 2022Comments
-
Š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); } } }