Android TextView长按弹出单词释义弹窗及选中高亮功能实现咨询
实现方案
1. 屏蔽系统默认文本选择菜单,自定义长按逻辑
无需保留android:textIsSelectable="true"属性,直接通过自定义触摸事件拦截系统默认行为即可:
- 给TextView设置长按监听器,获取点击位置对应的字符偏移量,再提取出完整的目标单词
- 重写TextView的
onCreateContextMenu方法返回空,彻底屏蔽系统自带的复制、分享菜单
示例代码如下:
textView.setOnLongClickListener { view -> val targetTv = view as TextView // 获取长按点对应的文本偏移位置 val offset = targetTv.getOffsetForPosition(event.x, event.y) val fullText = targetTv.text if (offset < 0 || offset >= fullText.length) return@setOnLongClickListener false // 提取当前偏移位置对应的完整单词 val (startPos, endPos, selectWord) = getWordByOffset(fullText, offset) // 触发高亮 setWordHighlight(targetTv, startPos, endPos) // 弹出自定义释义弹窗 showDefinitionPopup(selectWord) // 拦截事件,不触发系统默认逻辑 true } // 辅助方法:按偏移量提取完整单词,可自行调整边界规则适配中英文 private fun getWordByOffset(text: CharSequence, offset: Int): Triple<Int, Int, String> { var start = offset var end = offset // 向左匹配单词边界 while (start > 0 && Character.isLetterOrDigit(text[start - 1])) { start-- } // 向右匹配单词边界 while (end < text.length && Character.isLetterOrDigit(text[end])) { end++ } return Triple(start, end, text.subSequence(start, end).toString()) }
2. 实现选中单词高亮效果
通过Spannable配合BackgroundColorSpan实现区域高亮,每次选中新单词时先清除旧的高亮样式即可:
private fun setWordHighlight(tv: TextView, start: Int, end: Int) { val spannableText = SpannableString(tv.text) // 移除之前的所有高亮样式 val oldSpans = spannableText.getSpans(0, spannableText.length, BackgroundColorSpan::class.java) oldSpans.forEach { spannableText.removeSpan(it) } // 添加新的高亮,颜色可自行调整 spannableText.setSpan( BackgroundColorSpan(Color.parseColor("#FFFF00")), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE ) tv.text = spannableText }
可选优化
如果需要支持滑动调整选中范围,可以重写TextView的onTouchEvent方法,监听ACTION_MOVE事件,实时更新当前选中的单词位置和高亮效果即可。
内容的提问来源于stack exchange,提问作者Aman Sharma
相关产品推荐
相关产品推荐

