【发布时间】:2021-04-25 19:03:10
【问题描述】:
我在 MainActivity 的顶部工具栏上设置了一个 SearchView。用户点击搜索图标,然后从软键盘输入搜索字符。 ViewModel 观察者从 Room 数据库返回匹配数据,然后为 CardsAdapter 运行 setFilter() 方法来设置 RecyclerView 列表,该列表显示与搜索字符串匹配的 CardViews。我在 Adapter 的 onBindViewHolder() 中设置了 Spannable 代码,为每个返回的 CardView 突出显示与搜索字符串匹配的字符。
搜索代码返回了正确的 CardViews。但是,Spannable 代码未按预期工作。我在这里错过了什么?
以下是我正在尝试解决的结果:
-
如果在 SearchView 中输入了一个小“t”,
a) 那么只有第一个“t”被突出显示(绿色)。所有剩余的小“t” CardView EditText 行未突出显示。我想突出显示所有小“t”。
b) 没有大写“T”的 CardView 以绿色突出显示。我想 所有大写的“T”也会被突出显示。
这是一个显示两个问题的示例 CardView:只有第一个小“t”以绿色突出显示,而大写“T”根本不突出显示。
-
如果在 SearchView 中输入了大写“T”,
a) 那么只有第一个“T”被突出显示(绿色)。所有剩余的大写“T”都不是 突出显示。我希望突出显示所有“T”。
b) 没有一个带有小“t”的 CardView 以绿色突出显示。我想要所有 的小“t”也会被突出显示。
在 onBindViewHolder() 中,如果我将“String todoHighlight = card.getTodo()”附加到“.toLowerCase()”,则:
-
如果在 SearchView 中输入了一个小“t”,
a) 那么只有第一个“T”或“t”被突出显示(绿色)。所有剩余的“T”或“t”都是 没有突出显示。我希望它们都突出显示。
b) 如我所愿,大写的“T”以绿色突出显示。
-
如果在 SearchView 中输入了大写的“T”,
a) 没有一个带有小“t”或大写“T”的 CardView 以绿色突出显示。我希望它们都突出显示。
主活动
...
mSearchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName())); EditText mSearchEditText = mSearchView.findViewById(androidx.appcompat.R.id.search_src_text); mSearchEditText.setInputType(android.text.InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); // use the link to EditText of the SearchView so that a // TextWatcher can be used. mSearchEditText.addTextChangedListener(new TextWatcher() { @Override public void afterTextChanged(Editable s) { if (s.toString().length() > 0) { String queryText = "%" + s.toString() + "%"; mQuickcardViewModel.searchQuery(queryText).observe(MainActivity.this, searchQuickcards -> { searchList = searchQuickcards; if (!mSearchView.isIconified() && searchList.size() > 0) { cardsAdapter.setFilter(searchList, s.toString()); } });卡片适配器
...
public void setFilter(List<card> searchCards, String searchString) { mListItems = new ArrayList<>(); mListItems.clear(); mListItems.addAll(searchCards); this.searchString = searchString; notifyDataSetChanged(); } public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) { ... // also tried "String todoHighlight = card.getTodo().toLowerCase();" String todoHighlight = card.getTodo(); if (searchString != null && !searchString.isEmpty() && todoHighlight.contains(searchString)) { int todoStartPos = todoHighlight.indexOf(searchString); int todoEndPos = todoStartPos + searchString.length(); Spannable spanString2 = new SpannableString(itemHolder.cardBlankText2.getText()); if (spanString2 != null) { spanString2.removeSpan(itemHolder.getForegroundColorSpan()); itemHolder.cardBlankTextNumstotal.setText(spanString2); spanString2.setSpan(new ForegroundColorSpan(Color.GREEN), todoStartPos, todoEndPos, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); itemHolder.cardBlankText2.setText(spanString2); } }
修改后的代码有时可以工作,有时会崩溃:
in onBindViewHolder():
String todoSearchHighlight = mListItems.get(position).getTodo();
Spannable spannable = new SpannableString(todoSearchHighlight);
if (searchString != null && !TextUtils.isEmpty(searchString)) {
highLightText(spannable, todoSearchHighlight, 0);
itemHolder.cardBlankText2.setText(spannable);
}
else { // searchString == null
if (spannable != null) {
spannable.removeSpan(itemHolder.getForegroundColorSpan());
itemHolder.cardBlankText2.setText(todoSearchHighlight);
}
}
private void highLightText(Spannable spannable, String string, int start) {
int startPos = start + string.substring(start).toLowerCase(Locale.US).indexOf(searchString.toLowerCase(Locale.US));
int endPos = startPos + searchString.length();
if (string.substring(endPos).toLowerCase(Locale.US).contains(searchString.toLowerCase(Locale.US))){
highLightText(spannable, string, endPos);
}
ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(Color.GREEN);
spannable.setSpan(foregroundColorSpan, startPos, endPos, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
执行以下答案后出现 logcat 错误:
java.lang.IndexOutOfBoundsException: setSpan (-1 ... 0) 在 0 之前开始 在 android.text.SpannableStringInternal.checkRange(SpannableStringInternal.java:442) 在 android.text.SpannableStringInternal.setSpan(SpannableStringInternal.java:163) 在 android.text.SpannableStringInternal.setSpan(SpannableStringInternal.java:152) 在 android.text.SpannableString.setSpan(SpannableString.java:46) 在 com.todo.quickcards.adapter.CardsAdapter.highLightText(CardsAdapter.java:665) 在 com.todo.quickcards.adapter.CardsAdapter.onBindViewHolder(CardsAdapter.java:643)
【问题讨论】:
标签: android android-recyclerview spannable