I have added in the Toolbar a SearchView to filter some items.
@Override
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.menu, menu);
MenuItem searchItem = menu.findItem(R.id.search);
SearchView search = (SearchView) searchItem.getActionView();
autoComplete = search.findViewById(androidx.appcompat.R.id.search_src_text);
}
In my MainActivity I get a the list of items an pass it to my adapter:
ItemsArrayAdapter adapter = new ItemsArrayAdapter(this, itemList);
autoComplete.setAdapter(adapter);
And this is my adapter class:
public class ItemsArrayAdapter extends ArrayAdapter<Item> {
private List<Item> itemListFull;
ItemsArrayAdapter(@NonNull Context context, @NonNull List<Item> items) {
super(context, 0, items);
itemListFull = new ArrayList<>(items);
}
@NonNull
@Override
public Filter getFilter() {
return itemFilter;
}
@NonNull
@Override
public View getView(int position, View convertView, @NonNull ViewGroup parent) {
Item item = getItem(position);
if (convertView == null) {
//Inflate view
}
return convertView;
}
private Filter itemFilter = new Filter() {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
List<Item> suggestionList = new ArrayList<>();
if (constraint == null || constraint.length() == 0) {
suggestionList.addAll(itemListFull);
} else {
String filterPattern = constraint.toString().toLowerCase().trim();
for (Item item : itemListFull) {
if (item.name.toLowerCase().contains(filterPattern)) {
suggestionList.add(item);
}
}
}
results.values = suggestionList;
results.count = suggestionList.size();
Log.d(TAG, "size: " + suggestionList.size());
return results;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
List<Item> items = (List<Item>) results.values;
if (items != null) {
clear();
addAll(items);
}
notifyDataSetChanged();
}
@Override
public CharSequence convertResultToString(Object resultValue) {
return ((Item) resultValue).name;
}
};
}
The number of items that exist in the list is 26. When I write a letter for example c from word car the number of items that is returned is 26, even though the words that contain c are only 11. When I type the second letter a the number of items that is returned is 1 (which is correct) and the item is correctly displayed in the view. How to make the SearchView fire and return the correct number of item from the first time? Thanks.
That
search_src_textinSearchViewis a descendant ofAutoCompleteTextView, and it inherits most of its behavior from that class.AutoCompleteTextViewhas a default threshold of 2 characters. That is, it won't start filtering until you've input at least 2 characters, which explains why you were seeing the complete list when entering only one. We can fix that by lowering the threshold to 1.AutoCompleteTextViewhas thesetThreshold()method, so we could simply call that with an argument of 1. However, as you noted, this causes acan only be called from within the same library grouplint warning, because the specific subclass that the androidxSearchViewuses is marked@hidein the source. That can easily be suppressed with@SuppressLint("RestrictedApi"), but if you'd rather not use a restricted API, there is another way.We can set that threshold via the
android:completionThresholdXML attribute specified in a sub-style of the defaultAutoCompleteTextViewstyle that we then set as theautoCompleteTextViewStylein theActivity's theme. That is:Note that the
autoCompleteTextViewStyleattribute does not have theandroidprefix, because the actual class inSearchViewis a subclass ofAppCompatAutoCompleteTextView, which has its own default style attribute.