Android搜索视图定制:展示含指定关键词段落并高亮关键词
Android 关键词搜索+段落高亮完整实现方案
嘿,刚好做过类似的需求,给你梳理一套落地的技术方案,分四步走就能搞定:
1. 先把XML里的段落读出来
假设你的段落XML放在res/raw/paragraphs.xml,结构大概是这样:
<paragraphs> <p>Your first paragraph content, maybe contains theft...</p> <p>Second paragraph without the keyword...</p> <p>Third paragraph with theft again...</p> </paragraphs>
咱用XmlPullParser来解析,代码简单还高效:
private fun loadParagraphsFromXml(): List<String> { val paragraphs = mutableListOf<String>() val parser = resources.getXml(R.raw.paragraphs) var eventType = parser.eventType var currentParagraph = "" while (eventType != XmlPullParser.END_DOCUMENT) { when (eventType) { XmlPullParser.START_TAG -> { if (parser.name == "p") { currentParagraph = "" } } XmlPullParser.TEXT -> { currentParagraph += parser.text } XmlPullParser.END_TAG -> { if (parser.name == "p" && currentParagraph.isNotEmpty()) { paragraphs.add(currentParagraph.trim()) } } } eventType = parser.next() } return paragraphs }
2. 筛选出包含关键词的段落
遍历所有段落,判断是否包含目标关键词,记得做大小写不敏感处理(用户搜"Theft"也能匹配到):
fun filterParagraphs(keyword: String, allParagraphs: List<String>): List<String> { val lowerKeyword = keyword.lowercase() return allParagraphs.filter { paragraph -> paragraph.lowercase().contains(lowerKeyword) } }
3. 高亮段落里的关键词
用SpannableString来实现高亮,写个工具方法批量处理:
fun highlightKeyword(paragraph: String, keyword: String): SpannableString { val spannable = SpannableString(paragraph) val lowerParagraph = paragraph.lowercase() val lowerKeyword = keyword.lowercase() var startIndex = lowerParagraph.indexOf(lowerKeyword) while (startIndex != -1) { val endIndex = startIndex + keyword.length // 设置背景高亮,你也可以改成文字颜色 spannable.setSpan( BackgroundColorSpan(Color.YELLOW), startIndex, endIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE ) startIndex = lowerParagraph.indexOf(lowerKeyword, endIndex) } return spannable }
4. 展示处理后的结果
用RecyclerView来展示最方便,Adapter里绑定数据的时候直接用高亮后的SpannableString:
class ParagraphAdapter(private val highlightedParagraphs: List<SpannableString>) : RecyclerView.Adapter<ParagraphAdapter.ViewHolder>() { inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { val tvParagraph: TextView = itemView.findViewById(R.id.tv_paragraph) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val view = LayoutInflater.from(parent.context) .inflate(R.layout.item_paragraph, parent, false) return ViewHolder(view) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { holder.tvParagraph.text = highlightedParagraphs[position] } override fun getItemCount() = highlightedParagraphs.size }
最后整合调用的逻辑
// 初始化加载所有段落 val allParagraphs = loadParagraphsFromXml() // 搜索时的逻辑 fun onSearchKeyword(keyword: String) { if (keyword.isEmpty()) { // 关键词为空时可以展示所有段落,或者提示用户输入 return } // 筛选段落 val filtered = filterParagraphs(keyword, allParagraphs) // 批量高亮 val highlighted = filtered.map { highlightKeyword(it, keyword) } // 更新RecyclerView val adapter = ParagraphAdapter(highlighted) recyclerView.adapter = adapter }
这样就能实现你要的效果:搜单个关键词,只显示包含它的段落,还自动高亮关键词。如果需要调整高亮样式,直接改BackgroundColorSpan成其他Span就行~
内容的提问来源于stack exchange,提问作者lakshman kumar
相关产品推荐
相关产品推荐

