android - 在 ArrayAdapter 中使用过滤器时,SearchView 仅第二次触发
问题描述
我在工具栏中添加了一个 SearchView 来过滤一些项目。
@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);
}
在我的 MainActivity 中,我得到一个项目列表并将其传递给我的适配器:
ItemsArrayAdapter adapter = new ItemsArrayAdapter(this, itemList);
autoComplete.setAdapter(adapter);
这是我的适配器类:
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;
}
};
}
列表中存在的项目数是 26。例如,当我c
从 word中写一个字母car
时,返回的项目数是 26,即使包含的单词c
只有 11。当我键入第二个字母时,返回的项目a
数是返回的项目是 1(这是正确的),并且项目在视图中正确显示。如何使 SearchView 触发并从第一次返回正确数量的项目?谢谢。
解决方案
那search_src_text
inSearchView
是 的后代AutoCompleteTextView
,它从该类继承了大部分行为。AutoCompleteTextView
默认阈值为 2 个字符。也就是说,在您输入至少 2 个字符之前,它不会开始过滤,这就解释了为什么您在只输入一个字符时会看到完整的列表。我们可以通过将阈值降低到 1 来解决这个问题。
AutoCompleteTextView
有该setThreshold()
方法,所以我们可以简单地使用参数 1 调用它。但是,正如您所指出的,这会导致can only be called from within the same library group
lint 警告,因为 androidxSearchView
使用的特定子类已在源代码中标记@hide
。这可以很容易地用 来抑制@SuppressLint("RestrictedApi")
,但如果您不想使用受限制的 API,还有另一种方法。
我们可以通过android:completionThreshold
在默认样式的子样式中指定的 XML 属性设置该阈值AutoCompleteTextView
,然后将其设置为autoCompleteTextViewStyle
的Activity
主题中的 。那是:
<style name="AppTheme" parent="...">
...
<item name="autoCompleteTextViewStyle">@style/LowThreshold.AutoCompleteTextView</item>
</style>
<style name="LowThreshold.AutoCompleteTextView" parent="Widget.AppCompat.AutoCompleteTextView">
<item name="android:completionThreshold">1</item>
</style>
请注意,该autoCompleteTextViewStyle
属性没有android
前缀,因为实际的类SearchView
是 的子类AppCompatAutoCompleteTextView
,它有自己的默认样式属性。
推荐阅读
- google-apps-script - 如果选中/取消选中复选框,则应用程序脚本 onEdit 可跨多个工作表添加/清除时间戳
- python - 你能让这个功能更高效吗?谢谢
- javascript - 如何使用 Tampermonkey 填写 Google 表单的下拉列表和文本输入?
- postgresql - 如何插入一个空行,但正确进行串行更新?
- javascript - 在新的 DOM 主体中创建和查询元素
- python - 如何减少此函数中的参数数量
- javascript - 用ajax请求填充选择
- javascript - css 样式未在模态对话框中应用 - 我该如何解决?
- orm - 在 ORM Coldfusion 中使用动态生成的实体名称
- debugging - Firefox 开发者工具,同时打开 Inspector & debugger