如何在RecyclerView中高亮显示SearchView输入的过滤文本?
实现RecyclerView搜索结果高亮的完整方案
我来帮你搞定这个搜索文本高亮的问题!你之前在ViewHolder里尝试没生效,核心原因是没有把搜索文本传递到Adapter中,也没对TextView的文本做 Spannable 富文本处理。下面是一步步的修改方案:
第一步:修改你的BookAdapter,添加高亮逻辑
我们需要给Adapter增加存储搜索文本的变量,再写一个工具方法来生成带高亮效果的文本,最后在bind方法里替换原有的文本设置逻辑。
修改后的bookadapter.kt代码:
class bookadapter( private var booklist: ArrayList<Booksmodel>, private val itemClickListener: OnItemClicklistner ) : RecyclerView.Adapter<bookadapter.bookholder>() { // 新增:存储搜索文本 private var searchText: String = "" // 新增:设置搜索文本的方法 fun setSearchText(text: String) { this.searchText = text.lowercase(Locale.getDefault()) notifyDataSetChanged() // 更新UI } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): bookholder { val view = LayoutInflater.from(parent.context).inflate(R.layout.singlebook, parent, false) return bookholder(view) } fun filterlist(filterlist: ArrayList<Booksmodel>) { booklist = filterlist notifyDataSetChanged() } override fun onBindViewHolder(holder: bookholder, position: Int) { val book = booklist[position] holder.bind(book, itemClickListener, searchText) } override fun getItemCount(): Int { return booklist.size } inner class bookholder(view: View) : RecyclerView.ViewHolder(view) { val bookname: TextView = view.findViewById(R.id.recbooknametxt) val bookpublication = view.findViewById<TextView>(R.id.recbookpubtxt) val bookdept = view.findViewById<TextView>(R.id.recbookdepttxt) val bookimage = view.findViewById<ImageView>(R.id.recbookimg) // 修改bind方法,接收searchText参数 fun bind(book: Booksmodel, clicklistner: OnItemClicklistner, searchText: String) { // 对书名应用高亮效果 bookname.text = getHighlightedText(book.BookName ?: "", searchText) bookpublication.text = book.BookPublication bookdept.text = book.Department Picasso.get().load(book.BookImage).into(bookimage) itemView.setOnClickListener { clicklistner.onItemclick(book) } } // 核心:生成带高亮的Spannable文本 private fun getHighlightedText(originalText: String, searchText: String): SpannableString { val spannable = SpannableString(originalText) if (searchText.isEmpty()) return spannable val originalLower = originalText.lowercase(Locale.getDefault()) val startIndex = originalLower.indexOf(searchText) if (startIndex != -1) { val endIndex = startIndex + searchText.length // 设置高亮颜色(这里用红色,你可以换成自己需要的颜色,比如ContextCompat.getColor(itemView.context, R.color.your_highlight_color)) val highlightSpan = ForegroundColorSpan(Color.RED) spannable.setSpan( highlightSpan, startIndex, endIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE ) } return spannable } } interface OnItemClicklistner { fun onItemclick(books: Booksmodel) } }
第二步:修改Fragment中的filter方法,传递搜索文本
在你的books.kt里,每次搜索文本变化时,除了传递过滤后的列表,还要把当前的搜索文本传给Adapter:
修改后的filter方法:
private fun filter(text: String) { val filteredlist = ArrayList<Booksmodel>() val lowerCaseText = text.lowercase(Locale.getDefault()) for (item in booklist) { if (item.BookName?.lowercase(Locale.getDefault())?.contains(lowerCaseText) == true) { filteredlist.add(item) } } if (filteredlist.isEmpty()) { Toast.makeText(context, "No Data Found..", Toast.LENGTH_SHORT).show() } else { bookadapter.filterlist(filteredlist) } // 新增:把搜索文本传给Adapter bookadapter.setSearchText(text) }
关键逻辑说明
- SpannableString:Android提供的富文本工具,可以给文本的指定部分设置样式(颜色、大小、下划线等),这里我们用
ForegroundColorSpan来改变匹配文本的颜色。 - 大小写不敏感匹配:把原文本和搜索文本都转成小写,避免大小写导致的匹配失败。
- 空搜索文本处理:当搜索框为空时,直接返回原文本,保证正常显示。
- 实时更新:每次搜索文本变化时,调用
setSearchText并触发notifyDataSetChanged,让RecyclerView重新渲染带高亮的条目。
你可以根据自己的需求修改高亮的颜色(比如换成项目里的主题色),如果需要高亮多个匹配的子串,还可以扩展getHighlightedText方法,循环找到所有匹配的位置并设置Span。
内容的提问来源于stack exchange,提问作者Ashish Dawkhar
相关产品推荐
相关产品推荐

