如何在Android的TextView中实现文本高亮及自定义文本选择弹窗
Android TextView实现选中文本高亮+自定义操作弹窗方案
实现效果参考

第一步:基础配置(XML)
你之前配置的基础属性保留,额外加选中高亮颜色配置:
<TextView android:id="@+id/contentTv" android:layout_width="match_parent" android:layout_height="wrap_content" android:enabled="true" android:textIsSelectable="true" android:focusable="true" android:longClickable="true" <!-- 自定义选中文本的高亮背景色 --> android:textColorHighlight="#FFFF00" <!-- 可选:自定义选中文本的左右手柄图标 --> android:textSelectHandleLeft="@drawable/ic_select_handle" android:textSelectHandleRight="@drawable/ic_select_handle" android:textSelectHandle="@drawable/ic_select_handle"/>
第二步:替换系统默认操作弹窗,实现自定义菜单
系统默认的选中文本弹窗是通过ActionMode实现的,我们只需要给TextView设置自定义的ActionMode.Callback,重写菜单创建和点击逻辑即可:
Kotlin 示例代码
contentTv.customSelectionActionModeCallback = object : ActionMode.Callback { override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean { // 移除系统默认的菜单 menu?.clear() // 添加自定义菜单选项,顺序和文字按需调整 menu?.add(0, 1, 0, "高亮") menu?.add(0, 2, 1, "复制") menu?.add(0, 3, 2, "分享") menu?.add(0, 4, 3, "备注") return true } override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean { // 禁用系统默认的选中处理,返回false表示不需要系统处理 return false } override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean { // 获取选中的文本内容 val start = contentTv.selectionStart val end = contentTv.selectionEnd val selectedText = contentTv.text.substring(start, end) when(item?.itemId) { 1 -> { // 点击高亮选项,给选中区间文本设置永久高亮 val spannable = SpannableString(contentTv.text) spannable.setSpan( BackgroundColorSpan(Color.YELLOW), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE ) contentTv.text = spannable // 结束选中模式 mode?.finish() return true } 2 -> { // 自定义复制逻辑 val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager val clip = ClipData.newPlainText("selectedText", selectedText) clipboard.setPrimaryClip(clip) mode?.finish() return true } 3 -> { // 自定义分享逻辑 val shareIntent = Intent(Intent.ACTION_SEND).apply { type = "text/plain" putExtra(Intent.EXTRA_TEXT, selectedText) } startActivity(Intent.createChooser(shareIntent, "分享文本到")) mode?.finish() return true } 4 -> { // 自定义备注逻辑,弹出自定义弹窗即可 showCustomNoteDialog(selectedText) mode?.finish() return true } else -> return false } } override fun onDestroyActionMode(mode: ActionMode?) { // 选中销毁时的额外处理,按需添加 } }
注意事项
- 如果需要取消已有的高亮效果,遍历
Spannable中对应的BackgroundColorSpan移除即可 - 如果你需要弹窗完全自定义,不需要系统样式的ActionMode菜单,可以在
onCreateActionMode中返回false,自己监听TextView的选中变化,手动弹出自定义的PopupWindow即可 - 适配Android 10+的剪切板权限,复制功能不需要额外申请权限,读取剪切板内容需要适配权限要求
内容的提问来源于stack exchange,提问作者Emon Hossain Munna
相关产品推荐
相关产品推荐

