Android:使用 RecyclerView 和 ListAdapter 修复搜索文本突出显示

问题描述 投票:0回答:1

我在工具栏中有一个 SearchView,位于 CardView 的 RecyclerView 列表上方。 SearchView 可以正确地根据文本输入过滤列表。但是,ListAdapter 中“onBindViewHolder()”方法中用于在每个 CardView 上使用 Color.GREEN 突出显示搜索文本的代码不起作用。

我设置了一个布尔值“isSearchMatched”,当 CardView 具有与 SearchView 文本匹配的文本时,该布尔值会切换为 true。 然后,我在 onBindViewHolder() 中使用“isSearchMatched”,加上带有新 ArrayList 的 SubmitList() 用于 ListAdapter 来识别对 CardView 项目的更改,以便可以突出显示 CardView 中的搜索文本...不走运。

我在这里缺少什么?

主要活动

mSearchView.setOnQueryTextListener() {
    ...
    filter(newText)
}

private void filter(String searchText) {
        
    ArrayList<Card> searchList = new ArrayList<>();

    for (Card cardItem : mCards) {        
        if (cardItem.getTodo().toLowerCase().contains(searchText.toLowerCase(Locale.US))) {                    
            searchList.add(cardItem);
            **cardItem.setSearchMatched(true);**
        }
    }  
    if (!searchList.isEmpty()) {  
        adapter.setFilter(searchList, searchText);
}

Card.java // 模型项

@Entity(tableName = "cards_table")
public class Card implements Parcelable {

    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = "cardId")
    public int id;
    @ColumnInfo(name = "cardTodo")
    private String todo;
    @ColumnInfo(name = "cardMatchedSearchText")
    private boolean isSearchMatched = false;

    ...
@Override
public void writeToParcel(Parcel parcel, int flags) {
    parcel.writeInt(id);
    parcel.writeString(todo);
    parcel.writeByte((byte) (isSearchMatched ? 1 : 0));
}

private void readFromParcel(Parcel in) {
    id = in.readInt();        
    todo = in.readString();
    isSearchMatched = in.readByte() != 0;
}

public int getId() {
    return this.id;
}
public String getTodo() {
    return this.todo;
}
public boolean isSearchMatched() {
    return this.isSearchMatched;
}

public void setId(int id) {
    this.id = id;
}    
public void setTodo(String todo) {
    this.todo = todo;
}
public void setSearchMatched(boolean isSearchMatched) {
    this.isSearchMatched = isSearchMatched;
}

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    Card card = (Card) o;
    return Objects.equals(id, card.id) &&
           Objects.equals(todo, card.todo) &&               
           Objects.equals(isSearchMatched, card.isSearchMatched);
}         
     
@Override
public int hashCode() {
    return Objects.hash(id, todo, isSearchMatched);
}    

列表适配器

public class CardRVAdapter extends ListAdapter<Card, CardRVAdapter.ViewHolder> {

    private String searchString = "";
    public Spannable spannable;

    private static final DiffUtil.ItemCallback<Card> DIFF_CALLBACK = new DiffUtil.ItemCallback<Card>() {
    @Override
    public boolean areItemsTheSame(Card oldItem, Card newItem) {
        return oldItem.getId() == newItem.getId();
    }

    @Override
    public boolean areContentsTheSame(Card oldItem, Card newItem) {
        return oldItem.getTodo().equals(newItem.getTodo()) &&
               oldItem.isSearchMatched() == (newItem.isSearchMatched());
    }
};
    
    public void setFilter(List<Card> newSearchList, String adapSearchText) {

        if (newSearchList != null && !newSearchList.isEmpty()) {
            this.searchString = adapSearchText.toLowerCase(Locale.US);                
            submitList(new ArrayList<>(newSearchList));
        }
    }
  
    public class ViewHolder extends RecyclerView.ViewHolder {

        TextView cardBlankText2;  // displays text in the CardView and is matched against the user's search text input.
    }

    public ViewHolder(@NonNull final View itemView) {
        super(itemView);
         
        cardBlankText2 = itemView.findViewById(R.id.cardBlankText2);
    }

    void bindData(Card card, final int position) {

        // Highlight matches from search characters is Green color.
        if (searchString != null && !TextUtils.isEmpty(searchString)) {
            
            String todoSearchHighlightFromVH = cardBlankText2.getText().toString().toLowerCase();
            int offsetEnd2 = todoSearchHighlightFromVH.indexOf(searchString.toLowerCase(Locale.US));
            final Spannable spannable2 = new SpannableString(cardBlankText2.getText());
            spannable2.removeSpan(cardBlankText2);
            cardBlankText2.setText(spannable2);
 
            if (quickcard.isSearchMatched()) {
                for (int start2 = 0; start2 < todoSearchHighlightFromVH.length() && offsetEnd2 != -1; start2 = offsetEnd2 + 1) {

                    offsetEnd2 = todoSearchHighlightFromVH.indexOf(searchString.toLowerCase(Locale.US), start2);
                    if (offsetEnd2 == -1) {
                        break;
                    } else {
                        final ForegroundColorSpan foregroundColorSpan2 = new ForegroundColorSpan(Color.GREEN);
                        spannable2.setSpan(foregroundColorSpan2, offsetEnd2, offsetEnd2 + searchString.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                        cardBlankText2.setText(spannable2);
                    }
                }
            }
        }         


    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        
        final Card card = getItem(position);
        if (card != null) {        
            holder.bindData(card, position);
        }
    }
}
java android-recyclerview searchview spannable android-listadapter
1个回答
3
投票

问题是

            this.searchString = adapSearchText.toLowerCase(Locale.US);
            ArrayList<Card> tempList = new ArrayList<>(newSearchList); 
            submitList(tempList);

它适用于从当前列表中删除项目,但对于回收器视图上的现有项目,它不会触发

onBindViewHolder
,因为项目的数据不会改变。要修复它,您应该添加
searchString
Card
模型的属性,当您过滤时,您应该使用新的搜索字符串创建新的
Card
模型

© www.soinside.com 2019 - 2024. All rights reserved.