I want to search through RecyclerView
, I have List
(BaseOfCards is my getter&setter class)
My RecyclerViewAdapter<
I solved my problem
Make my class RecyclerViewAdapter implements Filterable
Add line private List<BaseOfCards> orig;
Add method getFilter
in RecyclerViewAdapter
public Filter getFilter() {
return new Filter() {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
final FilterResults oReturn = new FilterResults();
final List<BaseOfCards> results = new ArrayList<BaseOfCards>();
if (orig == null)
orig = items;
if (constraint != null){
if(orig !=null & orig.size()>0 ){
for ( final BaseOfCards g :orig) {
if (g.getCardName().toLowerCase().contains(constraint.toString()))results.add(g);
}
}
oReturn.values = results;
}
return oReturn;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
items = (ArrayList<BaseOfCards>)results.values;
notifyDataSetChanged();
}
};
Make MainActivity implements SearchView.OnQueryTextListener
and change method onQueryTextChange
:
@Override
public boolean onQueryTextChange(String newText) {
if ( TextUtils.isEmpty ( newText ) ) {
adapter.getFilter().filter("");
} else {
adapter.getFilter().filter(newText.toString());
}
return true;
}
From the time the other positive answer was done, I've now implemented a fast async filter using AsyncTask
in my FlexibleAdapter library, performance are very good with big lists, having animations too!
The Adapter is configurable to enable/disable properties in filtering result to increase speed when necessary. Another big advantage is also that interface is still responding to the user.
Test done in my Samsung S3 running Android 6: with a starting list of 10.450 items, from the moment the background process starts it takes ~1s to filter a character and select 3.890 items.
I've done also a Wiki page with all the details to use filter with the Adapter.
I want to add to ololoking answer.
In MainActivity
we should also add next code so it would work:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_layout, menu);
MenuItem searchItem = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
SearchManager manager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
searchView.setIconifiedByDefault(true);
searchView.setOnQueryTextListener(this);
return super.onCreateOptionsMenu(menu);
}
Thanks ololoking for your answer. It helped me.
In your adapter class extend filterable. Then override the public Filter getFilter().
@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 add search view and listener 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 SearchView
Using an autocompletetextview or an edittext i handled this one as following where
public List<SalesProductsItems> mItems
is the initial listitem instance and .
public static List<SalesProductsItems> filteredIt
is the instance used in displaying items.Since the 1st time the filter results is not null the mItems
instance will be equal to the filteredIt
instance (thus loosing the initial list) then on the publishResults
method right before mItems
looses the original values, I'm equating it to the passed instance originallist
. Hope it helps someone
private static class ProductsFilter extends Filter {
private final SalesProductsAdapter adapter;
private final List<SalesProductsItems> originalList;
private final List<SalesProductsItems> filteredList;
private ProductsFilter(SalesProductsAdapter adapter, List<SalesProductsItems> 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 == null || constraint.length() == 0)
filteredList.addAll(originalList);
else {
final String filterPattern = constraint.toString().toLowerCase().trim();
for (final SalesProductsItems it : originalList) {
if (it.getProduct().toLowerCase().contains(filterPattern)) {
filteredList.add(it);
}
}
}
results.values = filteredList;
results.count = filteredList.size();
return results;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
adapter.mItems = originalList;
if(results.count > 0) {
filteredIt.clear();
filteredIt.addAll((ArrayList<SalesProductsItems>) results.values);
adapter.notifyDataSetChanged();
} else {
filteredIt.clear();
filteredIt.addAll(adapter.mItems);
adapter.notifyDataSetChanged();
}
}
}